nicheware.platform.utilities.common.version

This namespace provides a set of functions supporting in-memory versioning of a map of assets represented by a clojure map.

There are groups of functions within the version namespace that deal with:

Function group Functions
version reference functions make-ref-name-fn find-element-with-ref-name, get-current-ref, get-first-asset-ref, replace-element-with-ref-name
version access functions get-ordered-versions, find-index, current-version-key, get-version, get-current, get-current-asset
version update functions rename-versions, rename-versioned-assets, timestamp-element, version-element, add-version, replace-current, set-version, mutate-version, delete-version, delete-asset-version, remove-unused-versions

A collection of versioned assets are assumed to be held in an asset map of the form:

{ <asset-key> {:current <modified-time>
              :name <asset-key>
              :versions { <modified-time-1> {<asset-v1> :name <asset-key> :modified-time <modified-time-1> }
                          <modified-time-2> {<asset-v2> :name <asset-key> :modified-time <modified-time-2> }
                        }
             }

 <asset-key-2> ....
}

Each asset has a unique key (asset-key). The key is used to

  • access the asset in the top level map of different assets
  • usually accessible as the :name attribute in the full versioned asset
  • usually accessible as the :name attribute in each of the versions of the asset.

Versioning is done by having a current version (:current) which is a key into different versions of the assets. The keys will normally be the time the version was created.

Functions are provided for adding a new version, removing existing versions etc.

In this simple implementation each version is a full copy of the assets state (any Clojure data structure).

It supports moving through past versions (or undo) simply by changing the modified time referenced by :current.

The functions also support the concept of a version reference, which is a vector of the form

[ <asset-key> <version-number>]

This would be used as reference pointer in any Clojure data type to reference a particular version of an asset.

version-number is normally just the modified time.

add-version

(add-version versioned-asset element)

Adds to the version list, if not already in the list, will append to the end. Becomes the new current version.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key-n> :versions {<mod-key-1> {<asset-1> ...}}}
  • element: New element to add to the list. Will set the :modified-time to be current time if not already set
  • returns: versioned-asset with element added as the latest version (i.e. :current updated)

current-version-key

(current-version-key assets asset-key)

Gets the current version key for the specified asset

  • assets: Map of assets, keyed by assets key, where each asset is versioned. {<asset-1-key> {:current <mod-time> :versions {:mod-time-1 <asset-v1> ...}}}
  • asset-key: Key into the asset map
  • returns: The :current of the asset matching the given key. nil if asset not present.

delete-asset-version

(delete-asset-version versioned-asset {:keys [modified-time], :as asset})

Same as delete version execpt it is given the version to be deleted rather than just the version number (modified-time).

If the version is the current one, then current becomes on the remaining versions.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key> :versions {<mod-key-1> {<asset-1-data>}}}
  • asset: Asset to be removed. Must include a :modified-time key, to identify the version to be deleted.
  • returns: updated versioned-asset, with version removed and :current updated if the current was deleted.

delete-version

(delete-version {:keys [current versions], :as versioned-asset} version)

Removes the specified version from the versioned asset. Ensures at least one asset version remains, (i.e, you cannot delete the last version) and that if the deleted asset is current a new asset (first) is selected as current.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key> :versions {<mod-key-1> {<asset-1>}}}
  • version: The version to be removed, typically the modified time.
  • returns: updated versioned-asset.

find-element-with-ref-name

(find-element-with-ref-name vec ref-key name)

Search’s a vector for the first element that has a version reference matching the given name.

Uses ref-key to determine which item in the element map is the version reference, then matches name against the first item of this reference.

Useful when searching for references to a versioned asset.

  • vec: Vector of elements. [ {<ref-key> [<asset-name> <asset-version] ...}, ...]
  • ref-key: The key within each element in the vector that contains the version reference of the form [<asset-key> <version>]
  • name: The asset key to be matched.
  • returns: The full element from vec which has a reference with that name.

find-index

(find-index versioned-asset {:keys [modified-time], :as element})

Treats the versions within the versioned-assets as a vector of version modification times, from smallest to highest, and returns the index within that vector of the provided elements modified time.

  • versioned-asset: Versioned asset to be searched for versions. {:versions {<mod-key-1> {<asset-1>}}}
  • element: Uses the :modified-time attribute as the value to find the index of.
  • returns index or nil if not found.

get-current

(get-current assets asset-key)

Gets the current version of the asset with the given key.

  • assets: Maps of assets, keyed by asset key, where each asset is versioned. {<asset-1-key> {:current <mod-time> :versions {:mod-time-1 <asset-v1> ...}}}
  • asset-key: Key of the asset for which the current version required.
  • returns: The current version of the asset.

get-current-asset

(get-current-asset {:keys [current versions], :as versioned-asset})

Gets the current version of the given versioned asset.

  • versioned-asset: Versioned asset to be searched for versions. {:current <mod-time> :versions {<mod-key-1> {<asset-1>}}}
  • returns: The current version of the asset.

get-current-ref

(get-current-ref assets asset-key)

Build an asset reference [name version] for the named asset using the current version

  • assets: Maps of assets, keyed by assets key, where each asset is versioned. {<asset-1-key> {:current <mod-time> :versions {:mod-time-1 <asset-v1> ...}}}
  • asset-key: Key into the asset map
  • returns: A reference to the current version of the asset. Format is [asset-key version]. version is usually modified time. if asset not in assets, reference will have nil as the version.

get-first-asset-ref

(get-first-asset-ref assets)

Access the first asset in the asset map and then extracts the reference to the current version for that asset

  • assets: Maps of assets, keyed by assets key, where each asset is versioned. {<asset-1-key> {:current <mod-time> :versions {:mod-time-1 <asset-v1> ...}}}
  • returns: A reference to the current version of the first asset. Format is [asset-key version]. version is usually modified time.

get-ordered-versions

(get-ordered-versions {:keys [versions], :as versioned-asset})

Extracts an ordered list of versions (from least to highest modified time) from the versioned-asset.

  • versioned-asset: Versioned asset to be searched for versions. {:versions {<mod-key-1> {<asset-1>}}}
  • returns: vector of versions (from smallest to highest) [<asset-1> ...]]

get-version

(get-version assets [asset-key version])

Gets the specified version of the named asset

  • assets: Maps of assets, keyed by assets key, where each asset is versioned. {<asset-1-key> {:current <mod-time> :versions {:mod-time-1 <asset-v1> ...}}}
  • reference: Vector of the asset-key (or name) and the required version (usually modified-time). [asset-key version]
  • returns: the asset with the required key and version.

make-ref-name-fn

(make-ref-name-fn ref-key name)

Makes a function that will test an element with a reference key item against the name (where name will match the first item of the ref-key value, i.e. the asset-key)

  • ref-key: The key in the element that contains the reference.
  • name: The value of the name part (or asset-key) of the reference that the returned function will check
  • returns: fn(element) where element should have a key of ref-key that is a reference [asset-key version] and the function will return true if the reference asset-key equals “name”

mutate-version

(mutate-version mutation versioned-asset asset)

Updates the version by either replacing the current or adding a new version. The action taken depends on whether the current one has the same mutation as passed in. If the same we dont bother creating a new version and just replace current.

  • mutation: The data to be added to the asset using the :mutation key.
  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key> :versions {<mod-key-1> {<asset-1>}}}
  • asset: asset data to have mutation added.
  • returns: updated versioned-asset with the mutated asset added as a new and latest version, or if the current assest has the same mutation, just replaced the current version with the new asset data.

remove-unused-versions

(remove-unused-versions versioned-asset)(remove-unused-versions {:keys [current versions], :as versioned-asset} pred-fn)

Removes any unused versions. A used version is either current or marked as starred (has a :starred true attribute) or returns true to the optional given predicate function.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-1> :versions {<mod-key-1 {:starred <bool> <asset-1-data>}}}
  • pred-fn: optional last argument should accept the version and return true if used. Defaults to a function that is always false
  • returns: versioned-asset with unused versions removed.

rename-versioned-asset

(rename-versioned-asset {:keys [versions], :as versioned-asset} new-name)

Will change the top level name of the asset and change the name in all the versions of the asset.

  • versioned-asset: Versioned asset to be searched for versions. {:current <mod-time> :name <asset-key> :versions {<mod-key-1> {:name <asset-key> ...}, <mod-key-2> {..} ...}}
  • new-name: New name to use for the asset, and hence for each version.
  • returns: updated versioned-asset map where the top level name and the name in the versions are modified to the new name.

rename-versions

(rename-versions versions new-name)

Renames element in the versions map, modifying the :name attribute to the new name.

  • versions: Versions map, each entry to have name updated. {<mod-key-1> {:name <asset-key> ...}, <mod-key-2> {..} ...}
  • new-name: New name to use for the asset, and hence for each version.
  • returns: updated version map where the name in the versions are modified to the new name.

replace-current

(replace-current {:keys [current], :as versioned-asset} asset)

Replaces the current version with the supplied version, but does not change any version number.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key> :versions {<mod-key-1> {<asset-1>}}}
  • asset: New asset to replace the existing current.
  • returns: Updated versioned-asset.

Should be used only when updates are to be made to the current version which you don’t want to affect versioning.

replace-element-with-ref-name

(replace-element-with-ref-name vec replacement-element ref-key name)

Searches a vector of elements where each element holds a reference [name, version]. It will search for the element that references the given name, and replace it with the supplied replacement element.

  • vec: Vector of elements to search. [ {<ref-key> [name, version] ...}, ...]
  • replacement-element: New element to replace the matching element.
  • ref-key: The key in the element that holds the reference [name/asset-key, version]
  • name: The name/asset-key in the reference that is being searched for.
  • returns: New vector with the suitable replacement element.

set-version

(set-version versioned-asset asset)

Sets the current version to the :modified-time of the given asset. Assumes this exists already as a version.

  • versioned-asset: Existing versioned asset, with map of current versions. {:current <mod-key> :versions {<mod-key-1> {<asset-1>}}}
  • asset: New asset to whose modified-time is to become the current version.
  • returns: Updated versioned-asset.

timestamp-element

(timestamp-element element)(timestamp-element element force)

Marks the element with the appropriate modification time.

  • element: Map in which a new :modified-time keyword to be added, if required.
  • force: optional 2 arity argument. If true will update :modified-time even if it exists. false by default.
  • returns: map with :modified-time set to current time in millis if not set or force = true.

version-element

(version-element element)

Prepare a new element for versioning. Will ensure timestamped and also not starred (as is new version)

  • element: Map which represent the version of an asset to be placed into list of versions.
  • returns: same element, but with appropriate :modified-time and no :starred attribute.