Documentation
¶
Overview ¶
Package catalog is the platform's own data catalog: the datasets its connections can see, their columns, the glossary, tags, domains and data products, and the curation written on them (#1916). This package holds the domain model and the reference form; pkg/catalog/postgres stores it.
Index ¶
- Constants
- Variables
- func Allows(kind Kind, name AspectName) bool
- func NormalizeAspect(kind Kind, name AspectName, value json.RawMessage) (json.RawMessage, error)
- func ParsePath(s string) ([]string, error)
- func Slug(name string) string
- type AspectEdit
- type AspectName
- type Aspects
- type BrowseEntry
- type BrowseQuery
- type Change
- type Column
- type ColumnInput
- type ConflictError
- type ContextDocument
- type CuratedQuery
- type Dataset
- type DatasetInput
- type DatasetQuery
- type DatasetSummary
- type DatasetType
- type Definition
- type DefinitionInput
- type DefinitionQuery
- type DefinitionSummary
- type Direction
- type DocumentInput
- type DocumentStore
- type Edge
- type Hop
- type InUseError
- type Incident
- type Kind
- type Link
- type Lister
- type Owner
- type Ref
- type Removal
- type SchemaDocument
- type Store
- type Use
- type WriterKind
Constants ¶
const ( IncidentActive = "active" IncidentResolved = "resolved" )
The states an incident can be in.
Variables ¶
var ErrAspectNotAllowed = errors.New("aspect not allowed on this entity")
ErrAspectNotAllowed is returned for an aspect the entity's kind does not carry.
var ErrInUse = errors.New("catalog definition in use")
ErrInUse is returned when a definition cannot be deleted because it is still used: a glossary node with terms or nodes under it, or a term, tag or domain a dataset or column carries.
var ErrInvalidAspect = errors.New("invalid aspect value")
ErrInvalidAspect is returned for an aspect value that does not decode into the aspect's shape.
var ErrInvalidDefinition = errors.New("invalid definition")
ErrInvalidDefinition refuses a definition that cannot be stored as given: no name, a name no slug can be derived from, or a parent that is not a glossary node or that its kind cannot have.
var ErrInvalidRef = errors.New("invalid catalog reference")
ErrInvalidRef is returned for a string that is not a well-formed catalog reference. Callers that route references by form treat it as "not mine".
var ErrNotFound = errors.New("catalog entity not found")
ErrNotFound is returned when a reference names no stored entity or change.
var ErrStale = errors.New("the aspect was written since it was read")
ErrStale refuses a write whose writer read an aspect that has been written since.
Functions ¶
func Allows ¶
func Allows(kind Kind, name AspectName) bool
Allows reports whether an entity of kind carries the aspect.
func NormalizeAspect ¶
func NormalizeAspect(kind Kind, name AspectName, value json.RawMessage) (json.RawMessage, error)
NormalizeAspect checks a value written to an aspect of an entity of kind and returns its canonical JSON, the form the store keeps. A JSON null clears the aspect and is returned as nil.
Types ¶
type AspectEdit ¶
type AspectEdit struct {
Ref Ref
Aspect AspectName
Value json.RawMessage
// Expect, when Checked, is the value the writer read the aspect as, nil
// for absent. WriteAspects refuses the whole write with ErrStale when the
// aspect holds anything else, so a value computed from what was read never
// replaces a write made since.
Expect json.RawMessage
Checked bool
}
AspectEdit is one aspect value for WriteAspects. A nil or JSON-null value clears the aspect.
type AspectName ¶
type AspectName string
AspectName names one kind of curation written on a catalog entity.
const ( AspectDescription AspectName = "description" AspectTags AspectName = "tags" AspectGlossaryTerms AspectName = "glossary_terms" AspectOwners AspectName = "owners" AspectDomain AspectName = "domain" AspectCustomProperties AspectName = "custom_properties" AspectStructuredProperties AspectName = "structured_properties" AspectDocumentationLinks AspectName = "documentation_links" AspectCuratedQueries AspectName = "curated_queries" AspectIncidents AspectName = "incidents" AspectContextDocuments AspectName = "context_documents" )
The aspects. Each is stored, versioned and rolled back on its own, so writing a dataset's tags never touches its description.
func AspectsFor ¶
func AspectsFor(kind Kind) []AspectName
AspectsFor returns the aspects an entity of kind carries, in a stable order.
type Aspects ¶
type Aspects struct {
Description string `json:"description,omitempty"`
Tags []string `json:"tags,omitempty"`
GlossaryTerms []string `json:"glossary_terms,omitempty"`
Owners []Owner `json:"owners,omitempty"`
Domain string `json:"domain,omitempty"`
CustomProperties map[string]string `json:"custom_properties,omitempty"`
StructuredProperties map[string][]any `json:"structured_properties,omitempty"`
DocumentationLinks []Link `json:"documentation_links,omitempty"`
CuratedQueries []CuratedQuery `json:"curated_queries,omitempty"`
Incidents []Incident `json:"incidents,omitempty"`
ContextDocuments []ContextDocument `json:"context_documents,omitempty"`
}
Aspects is the curation on one entity. An aspect never written is its zero value and is omitted from JSON.
GlossaryTerms and Domain hold references (mcp:glossary_term:<id>, mcp:domain:<id>); Tags holds tag names.
func (*Aspects) Set ¶
func (a *Aspects) Set(name AspectName, value json.RawMessage) error
Set decodes a stored or written value into the named aspect.
func (Aspects) WithText ¶
WithText returns a copy of the curation with every free-text value people and agents write passed through fn: descriptions, owners, property values, link and query descriptions, incident text and context documents. Names and references (tags, glossary terms, the domain, a query's SQL) are kept as they are. A reader that hands curation to a model scrubs it this way.
type BrowseEntry ¶
type BrowseEntry struct {
Name string `json:"name"`
// Reference is the dataset's reference, or for a group a dataset reference
// whose path is the group's, which fetching browses in turn.
Reference string `json:"reference"`
// Datasets is how many datasets a group holds; zero for a dataset.
Datasets int `json:"datasets"`
Type DatasetType `json:"type,omitempty"`
}
BrowseEntry is one entry of a browsed level: a dataset, or a path group holding datasets further down.
type BrowseQuery ¶
type BrowseQuery struct {
ConnectionKind string
Connection string
// Prefix is the path above the level listed; empty lists the top level.
Prefix []string
}
BrowseQuery names one level of a connection's datasets: the datasets and path groups directly under Prefix.
type Change ¶
type Change struct {
ID string `json:"id"`
Reference string `json:"reference"`
Aspect AspectName `json:"aspect"`
Version int `json:"version"`
Previous json.RawMessage `json:"previous,omitempty"`
Value json.RawMessage `json:"value,omitempty"`
WrittenBy string `json:"written_by"`
WrittenAt time.Time `json:"written_at"`
// Reverts names the change this one rolled back.
Reverts string `json:"reverts,omitempty"`
}
Change is one write of one aspect: what it replaced, what it wrote, who wrote it and when. A rollback is itself a change, pointing at the change it undid.
type Column ¶
type Column struct {
Name string `json:"name"`
DataType string `json:"data_type,omitempty"`
Ordinal int `json:"ordinal"`
Nullable bool `json:"nullable"`
Aspects Aspects `json:"aspects"`
}
Column is one column of a dataset: a stored row, not something parsed on demand out of the dataset's schema document.
type ColumnInput ¶
ColumnInput is one column as a writer declares it.
type ConflictError ¶
type ConflictError struct {
// Change is the change asked to be reverted.
Change string
// Reference and Aspect name what both changes wrote.
Reference string
Aspect AspectName
// Newer is the latest change to that aspect.
Newer Change
}
ConflictError refuses a revert of a change whose aspect was written again after it: undoing it would also discard the newer write.
func (*ConflictError) Error ¶
func (e *ConflictError) Error() string
Error implements the error interface.
type ContextDocument ¶
type ContextDocument struct {
ID string `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
ContentType string `json:"content_type,omitempty"`
Category string `json:"category,omitempty"`
}
ContextDocument is a document written about a dataset: how it is loaded, what a field means in practice, what to watch for.
type CuratedQuery ¶
type CuratedQuery struct {
Name string `json:"name"`
SQL string `json:"sql"`
Description string `json:"description,omitempty"`
}
CuratedQuery is a saved statement known to answer something about a dataset.
type Dataset ¶
type Dataset struct {
ID string `json:"id"`
Reference string `json:"reference"`
Ref Ref `json:"-"`
Name string `json:"name"`
Type DatasetType `json:"type"`
// SchemaResourceID is the managed resource a registered table was created
// from, when it was created from one.
SchemaResourceID string `json:"schema_resource_id,omitempty"`
// SchemaDocument is the reference of the connection's schema document the
// scan read the dataset from, when it was read from one (#1918).
SchemaDocument string `json:"schema_document,omitempty"`
Columns []Column `json:"columns"`
Aspects Aspects `json:"aspects"`
// RemovedAt is when a scan stopped seeing the dataset. Its curation stays
// readable, and a scan that sees it again clears this.
RemovedAt *time.Time `json:"removed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Dataset is one dataset and everything the catalog holds about it.
type DatasetInput ¶
type DatasetInput struct {
Ref Ref
Name string
Type DatasetType
SchemaResourceID string
// SchemaDocument is the filename of the connection's schema document the
// dataset was read from. Empty keeps the one already recorded.
SchemaDocument string
Columns []ColumnInput
}
DatasetInput is a dataset as a writer declares it: its identity, its type, its schema document and its columns in order. Curation is written separately, one aspect at a time, so declaring a dataset never overwrites curation.
type DatasetQuery ¶
type DatasetQuery struct {
Text string
ConnectionKind string
// Connection narrows the search to one connection of ConnectionKind.
Connection string
// Scoped limits the search to the connections in Within, each written
// "<connection kind>/<connection>"; a scoped search with none finds
// nothing. It is how a caller holds a search to the connections its
// persona reaches.
Scoped bool
Within []string
Tags []string
Limit int
Offset int
}
DatasetQuery narrows a dataset search. Text "*" or empty matches every dataset; other text matches the name, the path or the description, ignoring case.
type DatasetSummary ¶
type DatasetSummary struct {
Reference string `json:"reference"`
ConnectionKind string `json:"connection_kind"`
Connection string `json:"connection"`
Path string `json:"path"`
Name string `json:"name"`
Type DatasetType `json:"type"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags,omitempty"`
Domain string `json:"domain,omitempty"`
}
DatasetSummary is one dataset found by a search.
type DatasetType ¶
type DatasetType string
DatasetType is what kind of thing a dataset is at its source.
const ( DatasetTable DatasetType = "table" DatasetView DatasetType = "view" DatasetRegisteredTable DatasetType = "registered_table" DatasetWebhookTable DatasetType = "webhook_table" DatasetAPIOperation DatasetType = "api_operation" DatasetGraphQLOperation DatasetType = "graphql_operation" )
The dataset types a connection scan produces.
func (DatasetType) Valid ¶
func (t DatasetType) Valid() bool
Valid reports whether t is one of the dataset types.
type Definition ¶
type Definition struct {
ID string `json:"id"`
Reference string `json:"reference"`
Kind Kind `json:"kind"`
// Slug is the stable readable key a reference may use in place of the id.
// For a tag it is the tag's name.
Slug string `json:"slug"`
Name string `json:"name"`
// Parent is the glossary node a term or node sits under, as a reference.
Parent string `json:"parent,omitempty"`
Aspects Aspects `json:"aspects"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Definition is a glossary term, glossary node, domain, data product or tag.
type DefinitionInput ¶
DefinitionInput is a definition as a writer declares it. An empty Slug is derived from the name.
type DefinitionQuery ¶
type DefinitionQuery struct {
// Kinds are the definition kinds listed; empty lists every kind.
Kinds []Kind
// Parent lists the glossary terms and nodes directly under this glossary
// node reference.
Parent string
// Roots lists only the definitions under no glossary node. It is ignored
// when Parent is set.
Roots bool
// Text matches the name, the slug or the description, ignoring case.
Text string
Limit int
Offset int
}
DefinitionQuery narrows a definition listing.
type DefinitionSummary ¶
type DefinitionSummary struct {
Reference string `json:"reference"`
Kind Kind `json:"kind"`
Slug string `json:"slug"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
// Parent is the glossary node the definition sits under, as a reference.
Parent string `json:"parent,omitempty"`
// Children is how many glossary terms and nodes sit directly under a
// glossary node.
Children int `json:"children"`
}
DefinitionSummary is one definition found by a listing.
type Direction ¶
type Direction string
Direction is which way a lineage walk goes from its starting dataset.
type DocumentInput ¶
type DocumentInput struct {
ConnectionKind string
Connection string
Filename string
MIMEType string
Content []byte
}
DocumentInput is a schema document as a scan read it.
type DocumentStore ¶
type DocumentStore interface {
// PutDocument stores a document, recording a new version only when its
// content or media type changed, and reports whether it did.
PutDocument(ctx context.Context, in DocumentInput) (*SchemaDocument, bool, error)
// GetDocument reads one document with its content.
GetDocument(ctx context.Context, ref Ref) (*SchemaDocument, error)
// ListDocuments lists every document without its content, by connection
// and filename.
ListDocuments(ctx context.Context) ([]SchemaDocument, error)
}
DocumentStore keeps connections' schema documents.
type Edge ¶
type Edge struct {
Source string `json:"source"`
Target string `json:"target"`
WriterKind WriterKind `json:"writer_kind"`
// WriterRef names the writer: a script, an audited call, a registration.
WriterRef string `json:"writer_ref,omitempty"`
WrittenBy string `json:"written_by,omitempty"`
WrittenAt time.Time `json:"written_at"`
}
Edge is one lineage edge: data moved from Source to Target. Both are references, so an edge can name a dataset the catalog has not scanned yet.
type InUseError ¶
type InUseError struct {
Reference string
// Children is how many glossary terms and nodes sit under a glossary node.
Children int
// Entities is how many datasets and columns carry the definition.
Entities int
}
InUseError says what still uses a definition a delete was refused for.
func (*InUseError) Error ¶
func (e *InUseError) Error() string
Error implements the error interface.
type Incident ¶
type Incident struct {
ID string `json:"id"`
Type string `json:"type,omitempty"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
State string `json:"state"`
// Resolution is what was said when the incident was resolved.
Resolution string `json:"resolution,omitempty"`
}
Incident is a reported problem with a dataset. State is "active" or "resolved".
type Kind ¶
type Kind string
Kind names what a catalog reference points at.
const ( KindDataset Kind = "dataset" KindColumn Kind = "column" KindGlossaryTerm Kind = "glossary_term" KindGlossaryNode Kind = "glossary_node" KindTag Kind = "tag" KindDomain Kind = "domain" KindDataProduct Kind = "data_product" // KindSchemaDocument is a connection's schema document (an OpenAPI spec, a // GraphQL SDL) the catalog scan read its datasets from (#1918). KindSchemaDocument Kind = "schema_document" )
The catalog's entity kinds. Each is also the type segment of its mcp: reference, so mcp:glossary_term:<id> names a KindGlossaryTerm.
type Lister ¶
type Lister interface {
// ListDefinitions returns a page of definitions, ordered by name.
ListDefinitions(ctx context.Context, q DefinitionQuery) ([]DefinitionSummary, error)
// DeleteDefinition deletes a definition. It refuses with an *InUseError
// while anything uses it, and with ErrNotFound for an unknown one.
DeleteDefinition(ctx context.Context, ref Ref) error
// Uses returns the datasets and columns carrying a glossary term, a tag or
// a domain, at most limit of them, ordered by reference.
Uses(ctx context.Context, ref Ref, limit int) ([]Use, error)
// Browse lists one level of a connection's datasets that are not removed.
Browse(ctx context.Context, q BrowseQuery) ([]BrowseEntry, error)
}
Lister lists and resolves definitions, the uses of a definition, and the levels of a connection's datasets. The catalog store implements it.
type Owner ¶
Owner is one owner of an entity: a person's email or a group name, and the kind of ownership (technical_owner, business_owner, data_steward, ...).
type Ref ¶
type Ref struct {
Kind Kind
// ConnectionKind and Connection name the connection a dataset or column is
// seen through. Connection is the instance name, the same name an
// mcp:connection:(kind,name) reference carries.
ConnectionKind string
Connection string
// Path is the dataset's name under its connection, one element per dotted
// segment.
Path []string
// Column is the column name, set only on a KindColumn reference.
Column string
// Key is the id or slug of a glossary term, glossary node, domain or data
// product, the name of a tag, or a schema document's filename.
Key string
}
Ref identifies one catalog entity.
A dataset is determined by the connection that sees it and the path that connection names it by, so its reference is derived rather than assigned: mcp:dataset:(trino,warehouse,hive.sales.orders). The path is the dotted name the connection uses — catalog.schema.table for Trino, the operation id for an API connection, the dotted operation for a GraphQL one. A column adds its name: mcp:column:(trino,warehouse,hive.sales.orders,amount). The same table seen through two connections is two datasets.
A schema document belongs to its connection and is named by its filename: mcp:schema_document:(api,billing,"openapi.json").
A glossary term, glossary node, domain or data product is referenced by its stored id (mcp:glossary_term:<uuid>), so renaming one changes no reference to it; its slug is accepted in place of the id when reading. A tag is its name (mcp:tag:pii).
func DatasetRef ¶
DatasetRef returns the reference of the dataset a connection names by path.
func KeyRef ¶
KeyRef returns the reference of a glossary term, glossary node, domain, data product or tag.
func ParseRef ¶
ParseRef parses a catalog reference. A string that is not one — another platform reference, a string of another scheme, or a malformed catalog reference — is ErrInvalidRef.
func SchemaDocumentRef ¶
SchemaDocumentRef returns the reference of the schema document a connection keeps under filename.
func (Ref) Dataset ¶
Dataset returns the dataset a column reference belongs to, or the reference itself for a dataset.
func (Ref) PathString ¶
PathString is the dataset's path in reference form, each segment quoted where it needs to be.
type Removal ¶
type Removal struct {
ConnectionKind string
Connection string
// Types are the dataset types the scan produces; no other type is marked.
Types []DatasetType
// Keep are the references of the datasets the scan saw.
Keep []string
// Unread are dataset path prefixes, in reference form, the scan could not
// read; nothing under one is marked.
Unread []string
}
Removal is what a scan of one connection read, for marking the rest of it removed.
type SchemaDocument ¶
type SchemaDocument struct {
ID string `json:"id"`
Reference string `json:"reference"`
ConnectionKind string `json:"connection_kind"`
Connection string `json:"connection"`
Filename string `json:"filename"`
MIMEType string `json:"mime_type"`
SizeBytes int `json:"size_bytes"`
// Version counts the times the document's content changed; a scan that
// reads the same content again does not move it.
Version int `json:"version"`
UpdatedAt time.Time `json:"updated_at"`
// Content is the document itself. A listing leaves it empty.
Content []byte `json:"-"`
}
SchemaDocument is a connection's schema document as the catalog scan last read it: the OpenAPI spec an API connection's operations come from, the SDL a GraphQL connection's operations come from (#1918). It belongs to its connection, so it is read under the same connection boundary as the connection's datasets.
type Store ¶
type Store interface {
Lister
// PutDataset creates or updates a dataset and replaces its column set with
// the one given. Curation on a column that is still declared is kept; a
// column no longer declared is removed with its curation.
PutDataset(ctx context.Context, in DatasetInput) (*Dataset, error)
// GetDataset reads a dataset with its columns and all curation.
GetDataset(ctx context.Context, ref Ref) (*Dataset, error)
// PutDefinition creates or updates a glossary term, glossary node, domain,
// data product or tag, keyed by kind and slug.
PutDefinition(ctx context.Context, in DefinitionInput) (*Definition, error)
// GetDefinition reads a definition by its reference, whose key may be the
// id or the slug.
GetDefinition(ctx context.Context, ref Ref) (*Definition, error)
// WriteAspect writes one aspect of a dataset, column or definition and
// records the change. A nil or JSON-null value clears the aspect.
WriteAspect(ctx context.Context, ref Ref, name AspectName, value json.RawMessage, by string) (*Change, error)
// History lists the changes to one aspect, newest first.
History(ctx context.Context, ref Ref, name AspectName) ([]Change, error)
// Rollback restores the value a change replaced and records that as a new
// change.
Rollback(ctx context.Context, changeID, by string) (*Change, error)
// WriteAspects writes several aspects in one transaction: every edit is
// recorded as a change, or none is. Each value is checked as WriteAspect
// checks it.
WriteAspects(ctx context.Context, edits []AspectEdit, by string) ([]Change, error)
// RevertChanges rolls back several changes in one transaction. It refuses
// with a *ConflictError, reverting none, when an aspect one of them wrote
// has been written again since, and with ErrNotFound for an unknown change.
RevertChanges(ctx context.Context, changeIDs []string, by string) ([]Change, error)
// TaggedEntities returns the references of the datasets and columns whose
// tags aspect holds the tag, ordered by reference, at most limit of them.
TaggedEntities(ctx context.Context, tag string, limit int) ([]string, error)
// MarkRemoved marks the datasets a scan of one connection did not see as
// removed, and returns how many it marked. A dataset already marked is
// left as it is.
MarkRemoved(ctx context.Context, r Removal) (int, error)
// MarkDatasetRemoved marks one dataset removed, keeping its curation. A
// dataset the store does not hold is not an error.
MarkDatasetRemoved(ctx context.Context, ref Ref) error
// AddEdges records lineage edges; recording an edge again refreshes when
// it was written.
AddEdges(ctx context.Context, edges []Edge) error
// Lineage walks the edges from a dataset reference in one direction, at
// most maxDepth hops, each edge once at its shortest distance.
Lineage(ctx context.Context, ref string, direction Direction, maxDepth int) ([]Hop, error)
// DatasetsByPath returns the references of the datasets of one connection
// kind with the given path, one per connection that sees it, ordered by
// connection.
DatasetsByPath(ctx context.Context, connectionKind, path string) ([]string, error)
// SearchDatasets returns a page of datasets that are not removed and match
// the query, with their curation.
SearchDatasets(ctx context.Context, q DatasetQuery) ([]DatasetSummary, error)
}
Store is the catalog's storage.
type Use ¶
type Use struct {
// Reference is the dataset's or the column's.
Reference string `json:"reference"`
// Dataset is the dataset's reference, the same as Reference for a dataset.
Dataset string `json:"dataset"`
Name string `json:"name"`
// Column is set when a column, rather than the dataset, carries it.
Column string `json:"column,omitempty"`
Connection string `json:"connection"`
}
Use is one dataset or column carrying a definition.
type WriterKind ¶
type WriterKind string
WriterKind says what recorded a lineage edge.
const ( WriterScript WriterKind = "script" WriterSQL WriterKind = "sql" WriterRegistration WriterKind = "registration" WriterWebhook WriterKind = "webhook" WriterManual WriterKind = "manual" // WriterImport is an edge the one-time catalog import carried over (#1923). WriterImport WriterKind = "import" )
The writers of lineage edges.