Skip to content

Latest commit

 

History

History
184 lines (141 loc) · 8.4 KB

File metadata and controls

184 lines (141 loc) · 8.4 KB
page_title description
Plugin Development - Framework: Path Expressions
How to implement path expressions in the provider development framework. Path expressions are logic built on top of paths, which may represent one or more actual paths within schema data.

Path Expressions

Path expressions are logic built on top of paths, which may represent one or more actual paths within a schema or schema-based data. Expressions enable providers to work outside the restrictions of absolute paths and steps.

Usage

Example uses include:

Use cases which require exact locations, such as diagnostics, implement paths.

Concepts

Path expressions are an abstraction above paths. This page assumes knowledge of path concepts and implementations.

At its core, expressions implement the following on top of paths:

  • Information that designates whether path information is intended to be absolute, similar to paths, or relative, where it is assumed it will be merged with other absolute path information.
  • Parent steps, which enables backwards traversal towards the root of a schema in relative paths, after being merged with other absolute path information.
  • Path matching, which enables path information to logically return one or more actual paths.

Similar to paths, expressions are built using steps. There are expression steps which directly correspond to exact path steps, such as AtListIndex(), AtMapKey(), AtName(), AtSetValue(). Their implementation is the same. However, there are additional expression steps, such as AtAnyListIndex(), which cannot be represented in paths due to the potential for ambiguity.

Path matching is the notion that each expression step implements a method that logically determines if a given exact path step should match. For example, the AtAnyListIndex() expression step will accept any exact path step for a list index. Path matching with an expression is a collection of matching each expression step against each exact path step, after resolving any potential parent steps.

Every path expression must align with the schema definition or an error diagnostic will be raised when working with path matching within the framework. Provider-defined functionality that is schema-based, such as attribute validation and attribute plan modification, are provided an accurate current path expression since that functionality would not be able to determine its own path expression.

Building Path Expressions

The framework implementation for path expressions is in the path package, with the path.Expression type being the main provider developer interaction point.

Building Absolute Path Expressions

Call the path.MatchRoot() function with an attribute name or block name at the root of the schema to begin an absolute path expression.

Given this example schema with a root attribute named example_root_attribute:

schema.Schema{
	Attributes: map[string]schema.Attribute{
		"example_root_attribute": schema.StringAttribute{
			Required: true,
		},
	},
}

The call to path.MatchRoot() which matches the location of example_root_attribute string value is:

path.MatchRoot("example_root_attribute")

For blocks, the beginning of a path expression is similarly defined. Attribute and block names cannot overlap, so the framework automatically handles whether a path expression is referring to an attribute or block to start.

Given this example schema with a root block named example_root_block:

schema.Schema{
	Blocks: map[string]schema.Block{
		"example_root_block": schema.ListNestedBlock{
			NestedObject: schema.NestedBlockObject{/* ... */},
		},
	},
}

The call to path.MatchRoot() which matches the location of example_root_block list value is:

path.MatchRoot("example_root_block")

Once a path.Expression is started, it supports a builder pattern, which allows for chaining method calls to construct a full path.

This example shows a hypothetical path expression that points to any element of a list attribute to highlight the builder pattern:

path.MatchRoot("example_list_attribute").AtAnyListIndex()

This pattern can be extended to as many calls as necessary. The Building Expression Steps section covers the different framework schema types and any special path step methods.

Building Relative Path Expressions

Relative path expressions are, by nature, contextual to the actual path where they are defined in a schema. Call the path.MatchRelative() function to begin a relative path expression.

This example shows a relative path expression which references a child attribute:

schema.Schema{
	Attributes: map[string]schema.Attribute{
		"root_list_attribute": schema.ListNestedAttribute{
			NestedObject: schema.NestedAttributeObject{
				Attributes: map[string]schema.Attribute{
					"nested_list_attribute": schema.ListNestedAttribute{
						NestedObject: schema.NestedAttributeObject{
							Attributes: map[string]schema.Attribute{
								"deeply_nested_string_attribute": schema.StringAttribute{
									Required: true,
								},
							},
						},
						Required: true,
						Validators: []validator.List{
							exampleValidatorThatAcceptsExpressions(
								path.MatchRelative().AtAnyListIndex().AtName("deeply_nested_string_attribute"),
							),
						},
					},
					"nested_string_attribute": schema.StringAttribute{
						Required: true,
					},
				},
			},
			Required: true,
		},
	},
}

This example shows a relative path expression which references a different attribute within the same list index:

schema.Schema{
	Attributes: map[string]schema.Attribute{
		"root_list_attribute": schema.ListNestedAttribute{
			NestedObject: schema.NestedAttributeObject{
				Attributes: map[string]schema.Attribute{
					"nested_list_attribute": schema.ListNestedAttribute{
						NestedObject: schema.NestedAttributeObject{
							Attributes: map[string]schema.Attribute{
								"deeply_nested_string_attribute": schema.StringAttribute{
									Required: true,
								},
							},
						},
						Required: true,
						Validators: []validator.List{
							exampleValidatorThatAcceptsExpressions(
								path.MatchRelative().AtParent().AtName("nested_string_attribute"),
							),
						},
					},
					"nested_string_attribute": schema.StringAttribute{
						Required: true,
					},
				},
			},
			Required: true,
		},
	},
}

Building Expression Steps

Expressions follow similar schema type rules as paths, in particular Building Attribute Paths, Building Nested Attribute Paths, and Building Block Paths.

The following list shows the path.Expression type methods that behave similar to path.Path type methods.

  • AtListIndex()
  • AtMapKey()
  • AtName()
  • AtSetValue()

The following table shows the additional path.Expression type methods and their descriptions.

Expression Method Description
AtAnyListIndex() Will return matches for any list index. Can be used anywhere AtListIndex() can be used.
AtAnyMapKey() Will return matches for any map key. Can be used anywhere AtMapKey() can be used.
AtAnySetValue() Will return matches for any set value. Can be used anywhere AtSetValue() can be used.
AtParent() Will remove the last expression step, or put differently, will match the path closer to the root of the schema.