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
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.
@spec fetch(String.t(), String.t(), keyword()) :: {:ok, GeoGenius.ReleaseArtifacts.Artifact.t()} | {:error, GeoGenius.ArtifactError.t()}
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.
@spec list(String.t(), keyword()) :: {:ok, [GeoGenius.ReleaseArtifacts.Artifact.t()]} | {:error, GeoGenius.ArtifactError.t()}
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.
@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.