Documentation
¶
Overview ¶
Package entityfilter is about the where expressions that select ConfigHub entities, as a list's where parameter, a Filter's Where, and a Space's WhereTrigger do: what each entity type lets an expression name. Expressions over configuration data, such as where-resource, are another grammar, in the function api package.
Index ¶
Constants ¶
const ( // SlugCoreChars are the characters of a slug. A slash is not one, so <space>/<slug> is // unambiguous. SlugCoreChars = "\\-_.A-Za-z0-9" // SlugPrefixRegexpString matches a slug at the start of a string. SlugPrefixRegexpString = "^[A-Za-z0-9]([" + SlugCoreChars + "]*[A-Za-z0-9])?" // LabelKeyPrefixRegexpString matches a label key at the start of a string: more permissive // than Kubernetes, with dots and slashes anywhere inside. Annotation keys and the keys of // DeleteGates and DestroyGates have the same form. LabelKeyPrefixRegexpString = "^[A-Za-z0-9]([\\-_\\./A-Za-z0-9]*[A-Za-z0-9])?" )
The forms of the keys of map attributes, which an expression names after a dot. ConfigHub validates the keys it stores against the same expressions.
const MaxJSONPathLength = 512
MaxJSONPathLength bounds a single `Data.` path expression.
const WhereExtension = "x-confighub-where"
WhereExtension is the OpenAPI extension that publishes an entity type's attribute table: on each property of the entity's schema that an expression can name, as an Attribute, and on the schema itself, as a map of Attributes by name, for the qualified names that are no property of it.
Variables ¶
This section is empty.
Functions ¶
func DataTypeIsKeyedMap ¶
DataTypeIsKeyedMap reports whether a value of this type is addressed by key, which is what makes `Labels.owner` and `Tags.<uuid>` mean "one entry" rather than "an attribute of another entity".
The structured types are deliberately absent. PatchMap and the various lists are documents rather than keyed collections: nothing addresses an entry of one by name, and JSON-valued attributes are queried by path instead (see Revision.Conflicts).
func FieldNameToEntityName ¶
FieldNameToEntityName converts a field name to the corresponding entity name Examples: "UpstreamUnitID" -> "UpstreamUnit", "HeadRevisionNum" -> "HeadRevision"
Types ¶
type Attribute ¶
type Attribute struct {
// DataType is the attribute's type in an expression, which says which operators and literals
// it takes: a UUIDArray takes `?`, a StringMap is read by key, as in Labels.tier.
DataType api.DataType `json:"dataType"`
// References is the entity type an ID attribute names, and empty for any other attribute.
References string `json:"references,omitempty"`
// Expandable says the reference can prefix an attribute of what it names, as UpstreamUnitID
// does in UpstreamUnit.Slug: the entity's endpoints expand it.
Expandable bool `json:"expandable,omitempty"`
}
Attribute is what a where expression can do with one attribute of an entity type.
type AttributeTable ¶
AttributeTable is what a where expression can name, by entity type and then attribute name. A name the API nests and the entity's row does not, such as a Mutation's FunctionInvocation.Guards, is an attribute name too.
func (AttributeTable) Attribute ¶
func (t AttributeTable) Attribute(entityType, name string) (Attribute, bool)
Attribute returns an attribute of an entity type by name.
func (AttributeTable) ExpandableFields ¶
func (t AttributeTable) ExpandableFields(entityType string) []string
ExpandableFields returns the references of an entity type that can prefix attributes of what they name, sorted: the included fields to parse an expression over that type with, as the server does for a list of it or a Filter of it.
func (AttributeTable) HasEntityType ¶
func (t AttributeTable) HasEntityType(entityType string) bool
HasEntityType reports whether the table has the entity type.
func (AttributeTable) IsKeyedMap ¶
func (t AttributeTable) IsKeyedMap(field string) bool
IsKeyedMap reports whether a name before a dot is a keyed map rather than a prefix naming another entity, so that `Tags.<uuid>` reads one entry and `Unit.Slug` reads the Unit.
Derived from the attribute's declared data type rather than from a list of names. A list had to be kept in step with the models by hand, and it was not: `ChangeOrders` was missing, and so was `SkippedUnits`. What a missing entry does is not obvious, which is why none of them was noticed. The name after the dot is read as an attribute instead, and the identifier lexer stops at the first digit, so `ChangeOrders.ade0e7b9-...` was rejected as `ChangeOrders.ade`. Only ids beginning with a hex letter took that path, so the same query worked or failed depending on which uuid it was given, which reads as a flaky test rather than a bug.
The lookup is by name across every entity type in the table, which is what the list it replaced did: callers have only a name here.
type Attributes ¶
type Attributes interface {
// HasEntityType reports whether expressions can select entities of the type.
HasEntityType(entityType string) bool
// Attribute returns an attribute of an entity type by name.
Attribute(entityType, name string) (Attribute, bool)
// IsKeyedMap reports whether an attribute of that name, of any type, is a keyed map.
IsKeyedMap(name string) bool
}
Attributes is what a Parser reads names from. An AttributeTable is one; the server reads its own models directly.
type Expression ¶
type Expression struct {
// RelationalExpression holds the attribute's field name as Path, the operator, and the operand:
// a literal, or the name of another attribute when OperandEntityPrefix is set.
api.RelationalExpression
MapKey string // The key of a map attribute: Labels.<key>, ValidationErrors.<gate>, Values.<key>, DeleteGates.<key>
NestedMapKey string // For Permissions.<action>.UserIDs, UserIDs; the action is MapKey
// Attribute is what the table says about the attribute the term names. AttributeEntityType and
// AttributeName are where it is in the table: the type of the entity the prefix names, and the
// name it is declared under, which for a qualified name such as FunctionInvocation.Guards is
// not Path.
Attribute Attribute
AttributeEntityType string
AttributeName string
// Entity prefixes, for a term naming an attribute of another entity than the one filtered.
EntityPrefix string // The prefix, as "UpstreamUnit", or the filtered entity's own type
OperandEntityPrefix string // The same, for an operand that is an attribute
// IsExtendedTerm says the term names an attribute of an included entity, on either side, so it
// can only be evaluated once that entity is in hand.
IsExtendedTerm bool
// IsArrayElement is set by the `*` segment of an array-valued reference --
// `FromLink.*.Slug`, where the Unit's FromLinkID names a list and the expansion is a
// list of Links. It selects every element, so the term holds when any one of them
// satisfies it, the same quantification a `Data.` path uses for a segment that selects
// several values. Without the `*` an array-valued prefix is a parse error, since
// `FromLink.Slug` names no single value to compare.
IsArrayElement bool
OperandIsArrayElement bool // The same, for an operand that references an entity
// Truth-value test modifier: "IS TRUE", "IS FALSE", "IS NOT TRUE", "IS NOT FALSE"
// Applied as a post-fix modifier to the result of a binary expression.
// Useful for nullable columns: `MergeSourceID = 'uuid' IS NOT FALSE` matches rows
// where MergeSourceID equals the value OR is NULL.
TruthTest string
}
Expression is one term of a where expression, parsed and checked against an attribute table.
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser parses where expressions over one entity type, checking each name against an attribute table. It is the grammar only: what an expression means for storage, and the values of substituted entities, are the caller's.
func NewParser ¶
func NewParser(attributes Attributes, primaryEntityName string, includedFields []string, substitutedTypes map[string]string) *Parser
NewParser returns a parser of expressions over primaryEntityName. includedFields are the reference fields whose entities an expression may name by prefix, as UpstreamUnitID allows UpstreamUnit.Slug. substitutedTypes are the prefixes of entities whose values the caller will substitute, with the entity type of each, so the names after them can be checked.
func (*Parser) IncludedField ¶
TODO: Expanders should give us this IncludedField returns the reference field an entity prefix expands, as UpstreamUnitID for UpstreamUnit, and whether the parser was given it.