Skip to content

Repository files navigation

Bucket

Bucket

A library component of c3kit - Clean Coders Clojure Kit.

"Most men give advice by the bucket, but take it by the grain." - William R. Alger

Bucket Build Clojars Project License: MIT

What is bucket?

Bucket is a unified entity-storage API for Clojure and ClojureScript. The same domain code runs against any supported backend — Datomic, JDBC (Postgres, H2, MSSQL, SQLite), in-memory, and IndexedDB — because every backend implements the same c3kit.bucket.api/DB protocol. Define your schemas once with c3kit-apron, then transact, query, and look up entities through c3kit.bucket.api regardless of where the data lives.

Installation

deps.edn

{:deps {com.cleancoders.c3kit/bucket {:mvn/version "2.13.1"}}}

Leiningen

[com.cleancoders.c3kit/bucket "2.13.1"]

Hello World

The following example uses the explicit-db API (tx-, find-by-, entity-), which works without any global state setup and runs in a plain clj REPL once the dep is on the classpath.

(require '[c3kit.apron.schema :as s]
         '[c3kit.bucket.api :as db]
         '[c3kit.bucket.memory])  ; loads the :memory backend

;; Define a schema
(def widget
  {:kind  (s/kind :widget)
   :id    s/id
   :name  {:type :string}
   :color {:type :keyword}})

;; Create an in-memory database
(def my-db (db/create-db {:impl :memory} [widget]))

;; Save an entity (explicit-db variant)
(db/tx- my-db {:kind :widget :name "Sprocket" :color :red})
;; => {:kind :widget, :id 1001, :name "Sprocket", :color :red}

;; Find by attribute (returns a lazy seq)
(db/find-by- my-db :widget :name "Sprocket")
;; => ({:kind :widget, :id 1001, :name "Sprocket", :color :red})

;; Look up by id
(db/entity- my-db :widget 1001)
;; => {:kind :widget, :id 1001, :name "Sprocket", :color :red}

The id value (1001 above) is auto-generated and will vary. The same code shape works against any supported backend; only the {:impl ...} config map passed to create-db changes.

Supported backends

Impl key Platform Notes Guide
:memory CLJ / CLJS In-process, ephemeral
:re-memory CLJS Reagent-aware in-memory
:jdbc CLJ Postgres, H2, MSSQL, SQLite (+ pgvector, sqlite-vec)
:datomic CLJ Datomic on-prem (peer) docs/datomic-guide.md
:datomic-cloud CLJ Datomic Cloud (client) docs/datomic-guide.md
:indexeddb CLJS Browser persistent storage docs/indexeddb-guide.md
:re-indexeddb CLJS Reagent-aware IndexedDB docs/indexeddb-guide.md

Core concepts

Schemas

Schemas are plain Clojure maps validated by c3kit-apron. Every entity schema has a :kind declaration (via s/kind), an :id field, and attribute definitions that describe the type of each field.

(def order
  {:kind     (s/kind :order)
   :id       s/id
   :status   {:type :keyword}
   :subtotal {:type :bigdec}
   :placed-at {:type :instant}})

Attribute types include :string, :keyword, :long, :int, :boolean, :instant, :bigdec, :ref, and collection types like [:string] (a sequence of strings). See the apron docs for the full type reference.

The DB protocol

Every backend implements c3kit.bucket.api/DB. Consumers typically call the wrapper functions in c3kit.bucket.api (tx, find, find-by, ffind, ffind-by, entity, entity!, count, delete, reload, etc.).

Each wrapper has an explicit-db variant suffixed with - (e.g. tx-, find-by-, entity-) that accepts a DB instance as its first argument. Use these variants when working with multiple databases in the same process, or to avoid touching the global impl atom.

Migrations

Bucket includes a migration system for evolving your schema over time. Migrations are Clojure namespaces with numbered naming conventions; the migrator tracks which have run and executes new ones in order. See docs/migrations-guide.md for setup and usage.

Background tasks

c3kit.bucket.bg provides a lightweight scheduled-task manager backed by a ScheduledThreadPoolExecutor. Tasks are registered by key and store a :last-ran-at timestamp in the database, allowing persistent scheduling across restarts. Refer to the docstrings in src/clj/c3kit/bucket/bg.clj for the full public API.

Development

Running tests

# JVM tests
clj -M:test:spec
clj -M:test:spec -a        # auto runner

# ClojureScript tests
clj -M:test:cljs once
clj -M:test:cljs           # auto runner

The full SQL suite requires Postgres, MSSQL, SQLite, and sqlite-vec to be available locally. See CONTRIBUTING.md for environment setup details.

PostgreSQL local setup

$ sudo -u postgres createuser $(whoami)
$ sudo -u postgres createdb test
$ sudo -u postgres psql -d test -c "GRANT ALL ON SCHEMA public TO PUBLIC;"

Contributing

See CONTRIBUTING.md for development workflow, environment setup, and the release process. This project follows the Contributor Covenant Code of Conduct. Security issues should be reported privately — see SECURITY.md.

Deployment

Releases run in CI. clj -T:build deploy refuses to run outside GitHub Actions, so the sanctioned path always carries the CI check and leaves an audit trail.

  1. Open a PR bumping VERSION and CHANGES.md.
  2. Merge to master and wait for Bucket Build to go green. The version bump is part of the merged commit, so the commit CI validated is the commit that gets released.
  3. Actions → ReleaseRun workflow.
  4. Approve the clojars deployment when prompted.

The workflow verifies Bucket Build succeeded for that exact commit, builds the jar, publishes to Clojars, and only then pushes the version tag. A failed publish therefore leaves no tag.

clj -T:build jar builds without publishing. clj -T:build install installs to ~/.m2 for local testing.

Break glass

Only when the release workflow itself cannot run. This skips the CI check, so note its use in CHANGES.md for that release.

CLOJARS_USERNAME=<username> \
CLOJARS_PASSWORD=<deploy token> \
EMERGENCY_RELEASE=<the exact version in VERSION> \
  clj -T:build emergency-publish

CLOJARS_PASSWORD is a Clojars deploy token generated at https://clojars.org/tokens, not your account password. EMERGENCY_RELEASE must equal the version being released exactly; a mismatched or unset value aborts. It still refuses a dirty working tree and an already-tagged version.

License

MIT © Clean Coders.

About

No description, website, or topics provided.

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages