Liking cljdoc? Tell your friends :D

patcho.patch

A simple version migration system for Clojure applications.

Patcho provides a declarative way to define version-based patches that can be applied to migrate between different versions of your application or modules.

Key features:

  • Automatic patch sequencing based on semantic versioning
  • Support for both upgrades and downgrades
  • Topic-based organization for modular systems
  • Simple macro-based API

Basic usage: (require '[patcho.patch :as patch])

; Define current version (patch/current-version ::my-app "2.0.0")

; Define upgrade patches (patch/upgrade ::my-app "1.0.0" (println "Initial setup"))

(patch/upgrade ::my-app "2.0.0" (println "Major upgrade"))

; Apply patches (patch/apply ::my-app "1.0.0") ; Runs 2.0.0 upgrade (patch/apply ::my-app nil) ; Runs all upgrades

A simple version migration system for Clojure applications.

Patcho provides a declarative way to define version-based patches that can be
applied to migrate between different versions of your application or modules.

Key features:
- Automatic patch sequencing based on semantic versioning
- Support for both upgrades and downgrades
- Topic-based organization for modular systems
- Simple macro-based API

Basic usage:
  (require '[patcho.patch :as patch])
  
  ; Define current version
  (patch/current-version ::my-app "2.0.0")
  
  ; Define upgrade patches
  (patch/upgrade ::my-app "1.0.0"
    (println "Initial setup"))
  
  (patch/upgrade ::my-app "2.0.0"
    (println "Major upgrade"))
  
  ; Apply patches
  (patch/apply ::my-app "1.0.0")  ; Runs 2.0.0 upgrade
  (patch/apply ::my-app nil)        ; Runs all upgrades
raw docstring

*version-store*clj

Dynamic var for the version store.

Defaults to AtomVersionStore (in-memory). State is lost on restart unless you explicitly set a persistent store (FileVersionStore, database, etc.).

Set globally via set-store!, or temporarily via with-store macro. State is automatically migrated when switching stores.

Dynamic var for the version store.

Defaults to AtomVersionStore (in-memory). State is lost on restart unless
you explicitly set a persistent store (FileVersionStore, database, etc.).

Set globally via set-store!, or temporarily via with-store macro.
State is automatically migrated when switching stores.
raw docstring

_downgradecljmultimethod


_upgradecljmultimethod


applyclj

(apply topic)
(apply topic current)
(apply topic current target)

Applies version patches to migrate from one version to another.

With 1 arg: Migrates from installed version (read from version-store) to current-version. With 2 args: Migrates from 'current' to the topic's current version. With 3 args: Migrates from 'current' to 'target' version.

After successful migration, the new version is persisted to version-store.

Arguments: topic - Keyword identifying the module/component to patch current - Current version string (nil or "0" means start from beginning) target - Target version string (optional, defaults to topic's current version)

The function automatically:

  • Determines upgrade vs downgrade direction
  • Finds applicable patches between versions
  • Executes patches in correct order (oldest-first for upgrades, newest-first for downgrades)
  • Persists the new version to version-store

Returns: The target version if patches were applied, nil otherwise

Example: (apply ::my-app "1.0.0" "2.0.0") ; Upgrade from 1.0.0 to 2.0.0 (apply ::my-app "2.0.0" "1.0.0") ; Downgrade from 2.0.0 to 1.0.0 (apply ::my-app) ; Upgrade from installed to current

Applies version patches to migrate from one version to another.

With 1 arg:  Migrates from installed version (read from *version-store*) to current-version.
With 2 args: Migrates from 'current' to the topic's current version.
With 3 args: Migrates from 'current' to 'target' version.

After successful migration, the new version is persisted to *version-store*.

Arguments:
  topic   - Keyword identifying the module/component to patch
  current - Current version string (nil or "0" means start from beginning)
  target  - Target version string (optional, defaults to topic's current version)

The function automatically:
  - Determines upgrade vs downgrade direction
  - Finds applicable patches between versions
  - Executes patches in correct order (oldest-first for upgrades, newest-first for downgrades)
  - Persists the new version to *version-store*

Returns:
  The target version if patches were applied, nil otherwise

Example:
  (apply ::my-app "1.0.0" "2.0.0")  ; Upgrade from 1.0.0 to 2.0.0
  (apply ::my-app "2.0.0" "1.0.0")  ; Downgrade from 2.0.0 to 1.0.0
  (apply ::my-app)                    ; Upgrade from installed to current
raw docstring

available-versionsclj

(available-versions & topics)

Returns a map of topics to their current versions.

With no args: Returns all registered topic versions. With args: Returns versions only for specified topics.

Arguments: topics - Zero or more topic keywords to query

Returns: Map of {topic version-string} for registered topics

Example: (available-versions) ; => {:app "2.0.0" :db "1.5.0"} (available-versions :app) ; => {:app "2.0.0"} (available-versions :app :db :unknown) ; => {:app "2.0.0" :db "1.5.0"}

Returns a map of topics to their current versions.

With no args: Returns all registered topic versions.
With args: Returns versions only for specified topics.

Arguments:
  topics - Zero or more topic keywords to query

Returns:
  Map of {topic version-string} for registered topics

Example:
  (available-versions)                    ; => {:app "2.0.0" :db "1.5.0"}
  (available-versions :app)               ; => {:app "2.0.0"}
  (available-versions :app :db :unknown)  ; => {:app "2.0.0" :db "1.5.0"}
raw docstring

current-versioncljmacro

(current-version topic & body)

Defines the current/target version for a topic.

This version is used as the default target when calling apply with only 2 arguments.

Arguments: topic - Keyword identifying the module/component body - Should return a version string

Example: (current-version ::my-app "2.5.0")

; Can also compute version dynamically (current-version ::my-app (read-version-from-file))

Defines the current/target version for a topic.

This version is used as the default target when calling apply
with only 2 arguments.

Arguments:
  topic   - Keyword identifying the module/component
  body    - Should return a version string
  
Example:
  (current-version ::my-app "2.5.0")
  
  ; Can also compute version dynamically
  (current-version ::my-app 
    (read-version-from-file))
raw docstring

downgradecljmacro

(downgrade topic to & body)

Defines code to execute when downgrading FROM the specified version.

The body will be executed when applying patches that include this version in the downgrade path. Note: downgrade happens FROM this version to a lower version.

Arguments: topic - Keyword identifying the module/component to - Version string this downgrade migrates FROM body - Code to execute for the downgrade

Example: (downgrade ::database "2.0.0" (drop-column :users :preferences) (restore-legacy-settings))

Defines code to execute when downgrading FROM the specified version.

The body will be executed when applying patches that include this version
in the downgrade path. Note: downgrade happens FROM this version to a 
lower version.

Arguments:
  topic   - Keyword identifying the module/component
  to      - Version string this downgrade migrates FROM
  body    - Code to execute for the downgrade
  
Example:
  (downgrade ::database "2.0.0"
    (drop-column :users :preferences)
    (restore-legacy-settings))
raw docstring

level!clj

(level! topic)
(level! topic & more-topics)

Apply all pending patches for a component.

Reads the installed version from version-store, applies patches to reach current-version, and persists the new version.

Arguments: topic - Keyword identifying the module/component

Returns: The target version if patches were applied, nil if already at target.

Example: (level! :myapp/database)

Apply all pending patches for a component.

Reads the installed version from *version-store*, applies patches to reach
current-version, and persists the new version.

Arguments:
  topic - Keyword identifying the module/component

Returns:
  The target version if patches were applied, nil if already at target.

Example:
  (level! :myapp/database)
raw docstring

migrate-store!clj

(migrate-store! from-store to-store topics)

Migrate version state from one store to another.

Useful for bootstrapping: start with AtomVersionStore, setup database, then migrate state to database-backed store.

Args: from-store - Source VersionStore to read from to-store - Destination VersionStore to write to topics - Collection of topic keywords to migrate (or nil for all registered)

Returns: Set of migrated topics

Example: ;; Bootstrap with in-memory store (def bootstrap-store (->AtomVersionStore (atom {}))) (set-store! bootstrap-store) (level! :myapp/database)

;; Migrate to database store (migrate-store! bootstrap-store db nil) (set-store! db)

Migrate version state from one store to another.

Useful for bootstrapping: start with AtomVersionStore, setup database,
then migrate state to database-backed store.

Args:
  from-store - Source VersionStore to read from
  to-store   - Destination VersionStore to write to
  topics     - Collection of topic keywords to migrate (or nil for all registered)

Returns:
  Set of migrated topics

Example:
  ;; Bootstrap with in-memory store
  (def bootstrap-store (->AtomVersionStore (atom {})))
  (set-store! bootstrap-store)
  (level! :myapp/database)

  ;; Migrate to database store
  (migrate-store! bootstrap-store *db* nil)
  (set-store! *db*)
raw docstring

registered-topicsclj

(registered-topics)

Returns a set of all registered topics (components with current-version defined).

Returns: Set of topic keywords

Example: (registered-topics) ; => #{:synthigy/iam :synthigy/iam-audit :synthigy/dataset}

Returns a set of all registered topics (components with current-version defined).

Returns:
  Set of topic keywords

Example:
  (registered-topics)  ; => #{:synthigy/iam :synthigy/iam-audit :synthigy/dataset}
raw docstring

set-store!clj

(set-store! store)

Set the default version store globally.

Automatically migrates state from the previous store to the new one. This makes store transitions seamless (e.g., from bootstrap AtomVersionStore to database-backed store).

Arguments: store - Implementation of VersionStore protocol (or nil to clear)

Example: ;; Bootstrap with in-memory store (default) (level! :my/database)

;; Switch to DB - state auto-migrates (set-store! db)

(level! :my/app) ; Uses database store

Set the default version store globally.

Automatically migrates state from the previous store to the new one.
This makes store transitions seamless (e.g., from bootstrap AtomVersionStore
to database-backed store).

Arguments:
  store - Implementation of VersionStore protocol (or nil to clear)

Example:
  ;; Bootstrap with in-memory store (default)
  (level! :my/database)

  ;; Switch to DB - state auto-migrates
  (set-store! *db*)

  (level! :my/app)  ; Uses database store
raw docstring

topic-versionclj

(topic-version topic)

upgradecljmacro

(upgrade topic to & body)

Defines code to execute when upgrading TO the specified version.

The body will be executed when applying patches that include this version in the upgrade path.

Arguments: topic - Keyword identifying the module/component to - Version string this upgrade migrates TO body - Code to execute for the upgrade

Example: (upgrade ::database "2.0.0" (add-column :users :preferences :jsonb) (migrate-user-settings))

Defines code to execute when upgrading TO the specified version.

The body will be executed when applying patches that include this version
in the upgrade path.

Arguments:
  topic   - Keyword identifying the module/component
  to      - Version string this upgrade migrates TO
  body    - Code to execute for the upgrade
  
Example:
  (upgrade ::database "2.0.0"
    (add-column :users :preferences :jsonb)
    (migrate-user-settings))
raw docstring

versioncljmultimethod


VersionStorecljprotocol

Protocol for persisting version state across application restarts

Protocol for persisting version state across application restarts

read-versionclj

(read-version this topic)

Read the currently installed version for the given topic. Should return a version string or nil/"0" if not found.

Read the currently installed version for the given topic.
Should return a version string or nil/"0" if not found.

write-versionclj

(write-version this topic version)

Persist the installed version for the given topic. Called automatically by apply after successful migration.

Persist the installed version for the given topic.
Called automatically by apply after successful migration.
raw docstring

with-storecljmacro

(with-store store & body)

Execute body with a specific VersionStore bound to version-store.

Useful for testing or temporary overrides.

Arguments: store - Implementation of VersionStore protocol body - Expressions to execute with the store bound

Example: (with-store (->FileVersionStore ".test-versions") (apply ::my-app) (level! ::other-app))

Execute body with a specific VersionStore bound to *version-store*.

Useful for testing or temporary overrides.

Arguments:
  store - Implementation of VersionStore protocol
  body  - Expressions to execute with the store bound

Example:
  (with-store (->FileVersionStore ".test-versions")
    (apply ::my-app)
    (level! ::other-app))
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close