Lightning.Adaptors.Catalogue (Lightning v2.19.0)

View Source

Reads and writes for the adaptors and adaptor_versions tables.

Every read takes the :source (:npm | :local) explicitly. upsert_adaptor/1 is idempotent: checked_at advances on every call, updated_at only when a field actually changed, and version rows are replaced in the same transaction.

Summary

Functions

Full catalogue projection for a source: every adaptor's name, latest_version, repository, icon fields, and full version list.

ETag basis for the catalogue: {timestamp, version_row_count} for source, where timestamp is the later of MAX(adaptors.updated_at) and MAX(adaptor_versions.inserted_at), or nil when the source has no rows.

Delete every row for source.

Fetch a single adaptor by name within a source. Returns nil when no row matches.

The package_meta/0 projection of one (name, source) row, or nil. Unlike list_package_metas/1 this resolves excluded and deprecated adaptors too, so jobs already using one keep validating.

Full structs for a source, for callers that need the whole row, such as the Scheduler's diffing and the dump/seed tooling. Picker traffic uses the lighter list_package_metas/1.

Picker-facing lean projection for a source. Avoids the heavy schema_data JSONB column and skips the version join entirely.

All versions of an adaptor (name, source), in insertion order.

Maximum checked_at seen for source, or nil when the table is empty for that source. The Scheduler reads it at boot to time its first tick, and the Store reads it to tell whether the catalogue has ever loaded.

Advance checked_at for a known (name, source) row without loading it. No-op when no row matches.

Update only the icon columns for a single (name, source) row.

Upserts one adaptor record plus its version rows in one transaction. The source is read from the record, whose keys may be atoms or strings, as a decoded JSON snapshot gives them.

Types

catalogue_entry()

@type catalogue_entry() :: %{
  name: String.t(),
  latest_version: String.t(),
  repository: String.t() | nil,
  versions: [String.t()],
  icon_square_ext: String.t() | nil,
  icon_rectangle_ext: String.t() | nil,
  icon_square_sha256: binary() | nil,
  icon_rectangle_sha256: binary() | nil
}

package_meta()

@type package_meta() :: %{
  name: String.t(),
  latest_version: String.t(),
  description: String.t() | nil,
  deprecated: boolean(),
  icon_square_ext: String.t() | nil,
  icon_rectangle_ext: String.t() | nil,
  icon_square_sha256: binary() | nil,
  icon_rectangle_sha256: binary() | nil,
  has_schema: boolean()
}

source()

@type source() :: :npm | :local

Functions

catalogue(source)

@spec catalogue(source()) :: [catalogue_entry()]

Full catalogue projection for a source: every adaptor's name, latest_version, repository, icon fields, and full version list.

Excludes the packages listed in @excluded_names and any deprecated adaptor. A listed adaptor's deprecated versions are left out too.

catalogue_stamp(source)

@spec catalogue_stamp(source()) :: {DateTime.t() | nil, non_neg_integer()}

ETag basis for the catalogue: {timestamp, version_row_count} for source, where timestamp is the later of MAX(adaptors.updated_at) and MAX(adaptor_versions.inserted_at), or nil when the source has no rows.

version_row_count rides alongside the timestamp because deleting a version row moves neither max. It does lower the count.

delete_all_for_source(source)

@spec delete_all_for_source(source()) :: :ok

Delete every row for source.

get_adaptor(name, source)

@spec get_adaptor(String.t(), source()) ::
  Lightning.Adaptors.Catalogue.Adaptor.t() | nil

Fetch a single adaptor by name within a source. Returns nil when no row matches.

get_package_meta(name, source)

@spec get_package_meta(String.t(), source()) :: package_meta() | nil

The package_meta/0 projection of one (name, source) row, or nil. Unlike list_package_metas/1 this resolves excluded and deprecated adaptors too, so jobs already using one keep validating.

list_adaptors(source)

@spec list_adaptors(source()) :: [Lightning.Adaptors.Catalogue.Adaptor.t()]

Full structs for a source, for callers that need the whole row, such as the Scheduler's diffing and the dump/seed tooling. Picker traffic uses the lighter list_package_metas/1.

list_package_metas(source)

@spec list_package_metas(source()) :: [package_meta()]

Picker-facing lean projection for a source. Avoids the heavy schema_data JSONB column and skips the version join entirely.

Excludes the packages listed in @excluded_names and any deprecated adaptor.

list_versions(name, source)

All versions of an adaptor (name, source), in insertion order.

max_checked_at(source)

@spec max_checked_at(source()) :: DateTime.t() | nil

Maximum checked_at seen for source, or nil when the table is empty for that source. The Scheduler reads it at boot to time its first tick, and the Store reads it to tell whether the catalogue has ever loaded.

touch_checked_at(name, source)

@spec touch_checked_at(String.t(), source()) :: :ok

Advance checked_at for a known (name, source) row without loading it. No-op when no row matches.

The Scheduler uses this when a poll finds nothing changed. It is cheaper than a full upsert and never bumps updated_at.

update_icons(name, source, attrs)

@spec update_icons(String.t(), source(), map()) :: {integer(), nil}

Update only the icon columns for a single (name, source) row.

attrs may include any subset of :icon_square_ext, :icon_square_sha256, :icon_rectangle_ext, :icon_rectangle_sha256, :icon_square_etag, :icon_rectangle_etag. updated_at is advanced so callers can observe the change.

Sidesteps upsert_adaptor/1 deliberately: that helper rewrites the adaptor_versions rows in the same transaction, which is the wrong thing to do for an icon-only fix-up.

upsert_adaptor(record)

@spec upsert_adaptor(map()) :: {:ok, Lightning.Adaptors.Catalogue.Adaptor.t()}

Upserts one adaptor record plus its version rows in one transaction. The source is read from the record, whose keys may be atoms or strings, as a decoded JSON snapshot gives them.

checked_at advances on every call. updated_at advances only when some other field of the adaptor row differs from the existing row. Version rows are deleted and reinserted. Every row goes through its schema changeset first, so a corrupt strategy response cannot reach the database.

Raises if the transaction fails, for example on invalid input from a misbehaving strategy. The Scheduler relies on the success type only.