GeoGenius.ReleaseArtifacts (geo_genius v0.2.0)

Copy Markdown View Source

What files a release was built from, and where each one is on this machine.

GeoGenius stores area identity -- keys, names, codes, relations, centroids, boundaries -- and deliberately not a source's own wide attribute columns. A host that wants those keeps a projection: its own table, keyed (release_id, area_key), filled from the same artifacts the import consumed. Building one means answering two questions this module owns, and nothing about the file's contents, which the host owns entirely. See guides/projections.md.

Locating an artifact is not a Path.join/2. An artifact reaches the machine through GeoGenius.Cache, under a key the manifest supplied or the catalog derived, and an operator-supplied artifact has no url to fall back on -- the cache key is the only address it has. A caller that looked in priv/, or in the directory an import happened to stage a download in, works against a fixture and raises :enoent on a documented fresh install.

Reads the release a collection currently publishes. :release_id names a different one, published or not, which is how a projection is backfilled for a release before it goes live; it is checked against the collection first, so a stale id and another collection's id are both refused rather than answered with the wrong rows or none. Every function also takes the usual :repo, :prefix, and adapter options, and passes opts to the cache unchanged, so :cache_dir reaches GeoGenius.Caches.FileSystem.

Summary

Functions

The cache key an artifact row resolves under.

One artifact of a release, by the logical name its manifest gave it.

Every artifact a release composes, ordered by logical name -- the order GeoGenius.Catalog.release_artifacts/2 reads them in, so it is PostgreSQL's guarantee rather than this module's.

The local file one artifact of a release resolves to.

Functions

cache_key(row)

@spec cache_key(map()) :: {:ok, String.t()} | {:error, String.t()}

The cache key an artifact row resolves under.

Takes a row of the release_artifacts view, as GeoGenius.Catalog.release_artifacts/2 returns it. A key the manifest supplied -- stored on the row's metadata -- wins over the one the row's columns derive, because that is the whole reason a manifest may carry one: a licensed artifact an operator drops into a shared location has an address of its own and no url to fall back on.

A supplied key is validated the same way a derived one is. A manifest is reviewed, not trusted, and the metadata comes back out of jsonb rather than out of manifest validation, so a segment carrying a separator or a parent reference is refused here too. The error is the detail alone, without an artifact name, so each caller states the failure in its own terms.

GeoGenius.Pipeline.Artifacts resolves its downloads through this function, so a release read here is addressed exactly as the import that wrote it addressed it.

fetch(collection_key, logical_name, opts \\ [])

One artifact of a release, by the logical name its manifest gave it.

Resolves the artifact whether or not its file is present, so a caller can ask where a licensed artifact would be before an operator has placed it. path/3 is the same lookup for a caller that wants a file it can open.

list(collection_key, opts \\ [])

Every artifact a release composes, ordered by logical name -- the order GeoGenius.Catalog.release_artifacts/2 reads them in, so it is PostgreSQL's guarantee rather than this module's.

:release_id reads a release other than the published one. It must be a release of collection_key: an id the catalog does not carry, or one belonging to another collection, is refused rather than read.

Returns {:error, %GeoGenius.ArtifactError{reason: :no_published_release}} for a collection publishing nothing, rather than an empty list: a release that legitimately composes no artifacts is a different answer, and a caller repopulating a projection needs to tell them apart.

One artifact whose stored cache key is unusable fails the whole call. A catalog row nothing can address is a defect in what was registered, and quietly returning the rest would let a projection be rebuilt from a subset of the files it was supposed to read.

path(collection_key, logical_name, opts \\ [])

@spec path(String.t(), String.t(), keyword()) ::
  {:ok, Path.t()} | {:error, GeoGenius.ArtifactError.t()}

The local file one artifact of a release resolves to.

Returns {:error, %GeoGenius.ArtifactError{reason: :not_cached}} when nothing is at that path yet, naming both the path and the cache key, so an operator reading the message knows where to put the file. That is the whole point of returning an error here rather than the path regardless: a caller handed a path to a file that does not exist discovers it as an :enoent raised from inside whatever stream it opened, which names neither.