patch

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2026 License: MIT Imports: 19 Imported by: 0

README

parse/patch

JSON Patch and Merge Patch validation, SQL SET compilation, relation membership statements, and patch policy. Parsing checks the schema; application can still fail on runtime paths, tests, copy budgets, or destination constraints.

Usage and configuration

Guide Contents
Validation, typed documents, SQL compilation, and options Consumer guide
Relation statements and transaction requirements Consumer guide
Error catalog Consumer guide

Start with the runnable package example. The focused patch example is compiled and output-checked in the unit suite.

API reference

  • Schemas: GeneratePatchSchema[T], GenerateServerPatchSchema[T] (adds the parse:"server" fields, for the server's own writes), ServerFieldName, PatchSchema, PathSchema (AllowsOp, Nullable; EnumValues and Bounds advertise its value tags), DefaultPatchOps, ValidPatchOps
  • Parsing: NewParser(schema, cfg) (Parse, ParseOps), ParseMergePatch(body, schema, cfg), ParsedPatch (AuditInfo), PatchOperation, RawPatchOp, PatchOp
  • SQL: BuildPatchSQL, SQLDialect, PatchSQLResult (ChangePredicate), PatchSQLOption (WithStartParam, WithAutoTimestamp, WithAutoTimestampSQL, WithIncrement, WithTimeFunc, WithChangePredicate)
  • Relations: RelationPatchOp, RelationVerb, RenderRelationOp, RenderRelationOpOptions (Owner / RelationOwner and TargetVisible: guarded statements for a relation with a target table), RenderedRelationStatement, RelationPath
  • Policy: PatchPolicyConstraints, ValueConstraint, NewValueConstraint, PatchValidator, ApplyPatchPolicyConstraints, PatchPolicyFromWritableFields
  • Errors: ECode*, Codes

Code map

File Responsibility
patch.go Parser — RFC 6902 validation and value normalization
merge.go ParseMergePatch — RFC 7396
schema.go PatchOp, PatchSchema, PathSchema, PatchOperation, ParsedPatch
generate.go Schema generation from struct tags; default operations
validators.go Path validators from value tags: enum, minlen / maxlen, min / max, per element on an array path (minitems / maxitems count an array set whole: checkItems in patch.go)
sql.go BuildPatchSQL — per-column fold, merge and append compilation; the change predicate (WithChangePredicate)
relation_sql.go Relation patch rendering with junction tenancy
policy.go Patch policy and value constraints
errors.go E-codes

Dependencies

  • Imports: parse/core, parse/internal/{dialect,jsonmerge}
  • Imported by: parse, forge/dal/*, forge/feature
  • Package boundary: standalone Parse module

References

Package overview · Integration recipes

Documentation

Overview

Package patch provides JSON Patch (RFC 6902) and Merge Patch (RFC 7396) parsing with struct-tag-driven schema validation, SQL SET clause generation, and policy enforcement.

Struct Tags

Patch schema generation is driven by struct tags. The following tags are recognized by GeneratePatchSchema:

parse:"patch"           — include in patch schema
patch_ops:"replace,add" — allowed operations (add, remove, replace, move, copy, test, array_append)
enum:"active,inactive"  — restrict values to this set
db:"column_name"        — SQL column name for SET clause (default: snake_case of field name)

The tag key for field names (default "json") and column names (default "db") can be changed via core.WithFieldNameTag and core.WithColumnTag.

Parsing

Parser validates JSON Patch documents against a PatchSchema:

p := patch.NewParser(schema, nil)
parsed, err := p.Parse(body) // validates operations, pointers, nullability, values, enums

ParseMergePatch handles RFC 7396 Merge Patch (plain JSON with null = remove):

parsed, err := patch.ParseMergePatch(body, schema, nil)

SQL Generation

BuildPatchSQL converts a ParsedPatch into a parameterized SQL SET clause, one expression per column; operations SQL cannot express (move, copy, test, nested paths) are rejected, and merge-patch objects merge into the stored document:

result, err := patch.BuildPatchSQL(parsed, filter.PostgresDialect{},
    patch.WithAutoTimestamp("updated_at"),
)
// result.SetClause = "name = $1, status = $2, updated_at = $3"
// result.Args = ["new-name", "active", core.FormatTimestamp(now)]

WithChangePredicate also renders PatchSQLResult.ChangePredicate, true for a row the patch's columns change; ANDed into the UPDATE's WHERE, it writes, stamps and counts only those rows.

Policy Enforcement

ApplyPatchPolicyConstraints validates parsed patches against policy rules: forbidden paths, allowed/denied values, regex patterns, and custom validators.

pc := &patch.PatchPolicyConstraints{
    ForbiddenPaths: []string{"/tenant_id", "/internal_*"},
    ValueConstraints: map[string]*patch.ValueConstraint{
        "/status": {AllowedValues: []any{"active", "inactive"}},
    },
}
err := patch.ApplyPatchPolicyConstraints(parsed, pc, subject)

Index

Constants

View Source
const (
	ECodeOpNotAllowed core.Code = "E2064"
	// ECodePathTooDeep shares E2074 with filter's ECodeDepthExceeded: one
	// ParserConfig.MaxDepth bounds filter nesting and patch pointer depth.
	ECodePathTooDeep core.Code = "E2074"
	ECodeTooManyOps  core.Code = "E2066"
	// ECodeInputTooLarge shares E2063 with filter: one MaxInputSize bounds
	// filter and patch bodies.
	ECodeInputTooLarge        core.Code = "E2063"
	ECodeInvalidPatchOp       core.Code = "E2075"
	ECodePatchFieldNotFound   core.Code = "E2076"
	ECodePatchValueInvalid    core.Code = "E2077"
	ECodePatchSchemaNotFound  core.Code = "E2078"
	ECodePatchPolicyForbidden core.Code = "E2084"
	ECodePatchPolicyValue     core.Code = "E2085"
	ECodeInvalidJSON          core.Code = "E2086"

	// relation-patch error codes.
	ECodeRelationVerbNotAllowed core.Code = "E2117"
	ECodeRelationValueInvalid   core.Code = "E2118"
	ECodeRelationPatchTooLarge  core.Code = "E2119"

	//  / P-13i — SQL-compilation refusals, in the parse gap
	// E2068-E2069.
	ECodeTestOpSQL        core.Code = "E2068"
	ECodeSQLColumnMissing core.Code = "E2069"

	// an accepted operation BuildPatchSQL cannot express
	// (move, copy, a nested JSON Pointer path) is rejected, never skipped.
	ECodeOpNotSQLCompilable core.Code = "E2070"
)

Error codes for patch operations.

View Source
const DefaultMaxOperations = 50

DefaultMaxOperations is the operation limit used by GeneratePatchSchema and GenerateServerPatchSchema. Callers constructing a PatchSchema choose its limit.

Variables

ValidPatchOps is the set of all recognized patch operations.

Functions

func ApplyPatchPolicyConstraints

func ApplyPatchPolicyConstraints(patch *ParsedPatch, pc *PatchPolicyConstraints, subject *core.PolicySubject) error

ApplyPatchPolicyConstraints validates a ParsedPatch against policy constraints.

func Codes

func Codes() []core.Code

Codes returns the codes defined by this package.

func DefaultPatchOps

func DefaultPatchOps() map[core.FieldType][]PatchOp

DefaultPatchOps returns a defensive copy of the package's default FieldType -> patch-ops map. Callers can mutate the returned map without affecting the package-level defaults or other callers.

func ServerFieldName

func ServerFieldName(g *core.SchemaGenerator, field *core.Field) (name string, ok bool)

ServerFieldName returns the patch path name of a server field: its external name, or its column when the field-name tag hides it. ok is false for a field that is not a server field.

func ValidateTransferValue

func ValidateTransferValue(op *PatchOperation, value any, codec core.Codec, index int) error

ValidateTransferValue validates the runtime source of a copy or move against its destination. The source must be resolved from the document at the current operation, after earlier operations have run.

Types

type ParsedPatch

type ParsedPatch struct {
	Operations        []*PatchOperation
	EstimatedCost     int
	AffectedPaths     []string
	PolicyConstraints *PatchPolicyConstraints
}

ParsedPatch is the result of parsing a JSON Patch document.

func ParseMergePatch

func ParseMergePatch(body []byte, schema *PatchSchema, config *core.ParserConfig) (*ParsedPatch, error)

ParseMergePatch parses a JSON Merge Patch (RFC 7396) body into a ParsedPatch.

func ParseMergePatchMap

func ParseMergePatchMap(raw map[string]any, schema *PatchSchema, config *core.ParserConfig) (*ParsedPatch, error)

ParseMergePatchMap is ParseMergePatch for a merge patch already decoded, or built by the server: a nested map merges into a document member, any other value — a Go value of the path's type included (time.Time, uuid.UUID, a struct) — replaces, and null removes or clears. Null is whatever encoding/json writes as null: nil, or a nil pointer, map or slice. It avoids the JSON round trip of building a body only to parse it again.

func (*ParsedPatch) AuditInfo

func (p *ParsedPatch) AuditInfo() map[string]any

AuditInfo returns a map of audit-relevant information.

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser parses and validates JSON Patch documents.

func NewParser

func NewParser(schema *PatchSchema, config *core.ParserConfig) *Parser

NewParser creates a new patch Parser.

func (*Parser) Parse

func (p *Parser) Parse(body []byte) (*ParsedPatch, error)

Parse validates and parses a JSON Patch document from JSON bytes.

func (*Parser) ParseOps

func (p *Parser) ParseOps(ops []RawPatchOp) (*ParsedPatch, error)

ParseOps validates pre-decoded patch operations against the schema. Use this when the input has already been decoded from a non-JSON format (protobuf, msgpack, YAML, etc.).

type PatchOp

type PatchOp string

PatchOp represents a JSON Patch operation type.

const (
	PatchOpAdd     PatchOp = "add"
	PatchOpRemove  PatchOp = "remove"
	PatchOpReplace PatchOp = "replace"
	PatchOpMove    PatchOp = "move"
	PatchOpCopy    PatchOp = "copy"
	PatchOpTest    PatchOp = "test"

	// PatchOpArrayAppend is the extension to JSON Patch RFC 6902
	// for atomic single-statement array append. BuildPatchSQL renders it
	// to dialect-specific SQL:
	//
	//   Postgres: col = array_append(COALESCE(col, '{}'), $1)
	//   SQLite:   col = json_insert(COALESCE(col, '[]'), '$[#]', $1)
	//
	// Concurrent appenders converge without read-modify-write.
	PatchOpArrayAppend PatchOp = "array_append"
)

type PatchOperation

type PatchOperation struct {
	Op     PatchOp
	Path   string
	From   string
	Value  any
	Schema *PathSchema

	// Merge marks an op derived from an RFC 7396 merge patch whose value is
	// an object — it requires RECURSIVE merge semantics, not whole-value
	// replace. The apply path deep-merges via
	// internal/jsonmerge; BuildPatchSQL compiles it to json_patch on SQLite
	// and per-level jsonb construction on PostgreSQL, so sibling keys survive.
	Merge bool
}

PatchOperation represents a validated patch operation.

type PatchPolicyConstraints

type PatchPolicyConstraints struct {
	ForbiddenPaths   []string
	ValueConstraints map[string]*ValueConstraint
	Validators       []PatchValidator
}

PatchPolicyConstraints holds policy restrictions for patch operations.

func PatchPolicyFromWritableFields

func PatchPolicyFromWritableFields(allPaths []string, writable map[string]bool) *PatchPolicyConstraints

PatchPolicyFromWritableFields builds PatchPolicyConstraints with ForbiddenPaths for every path NOT in the writable map.

type PatchSQLOption

type PatchSQLOption func(*patchSQLConfig)

PatchSQLOption configures BuildPatchSQL behavior.

func WithAutoTimestamp

func WithAutoTimestamp(col string) PatchSQLOption

WithAutoTimestamp adds an automatic timestamp column to the SET clause.

func WithAutoTimestampSQL

func WithAutoTimestampSQL(col, expr string) PatchSQLOption

WithAutoTimestampSQL is WithAutoTimestamp with the column set to a SQL expression — the database's clock, NOW() — instead of a bound time, for a repository whose other writes stamp the database's clock: two clocks make timestamps incomparable once they skew.

func WithChangePredicate added in v0.8.0

func WithChangePredicate() PatchSQLOption

WithChangePredicate also renders PatchSQLResult.ChangePredicate, the condition under which the SET clause changes a row.

func WithIncrement added in v0.6.0

func WithIncrement(col string) PatchSQLOption

WithIncrement also sets col to one more than it holds — a version the server moves on every write (once, even if the patch sets it). Each WithIncrement adds a column.

func WithStartParam

func WithStartParam(n int) PatchSQLOption

WithStartParam offsets the SET clause's placeholders by n: the first is n+1, as with filter.WithStartParam, so one zero-based offset composes both builders. Default 0 (first placeholder $1).

func WithTimeFunc

func WithTimeFunc(fn func() time.Time) PatchSQLOption

WithTimeFunc overrides the function used to generate timestamps.

type PatchSQLResult

type PatchSQLResult struct {
	// SetClause is the comma-separated `col = $N` fragment ready to drop
	// into UPDATE … SET. Empty when the patch only touches relation
	// fields (junction-only patches).
	SetClause string

	// Args are the bound values for SetClause placeholders, in $N order.
	Args []any

	// ParamCount is the number of placeholders consumed by SetClause.
	// Callers append filter params starting at startParam + ParamCount.
	ParamCount int

	// ChangePredicate, rendered with WithChangePredicate, is true for a row
	// the SET clause's patch columns would change: a parenthesized OR of
	// null-safe comparisons of each column with the expression it is set to,
	// over the SET clause's own placeholders and no arguments of its own. It
	// leaves out the auto-timestamp and increments, so ANDed into an UPDATE's
	// WHERE it keeps them from moving on a row the patch leaves as it is.
	// Empty when SetClause is.
	ChangePredicate string

	// Empty is true when neither the column SET clause nor any relation
	// op produced output — the caller can short-circuit with no DB writes.
	Empty bool

	// RelationOps holds parsed-but-unrendered junction operations
	// extracted from the patch. The repository decorator
	// runs these alongside the owner UPDATE in a single transaction:
	// the UPDATE runs first (or is skipped when SetClause is empty),
	// then for each RelationOp the decorator emits a junction
	// DELETE / INSERT bound to the affected owner PKs returned by the
	// UPDATE … RETURNING clause.
	RelationOps []RelationPatchOp
}

PatchSQLResult holds the generated SQL SET clause and arguments.

func BuildPatchSQL

func BuildPatchSQL(patch *ParsedPatch, dialect SQLDialect, opts ...PatchSQLOption) (*PatchSQLResult, error)

BuildPatchSQL converts a ParsedPatch into a SQL SET clause and a list of relation patch ops.

Scalar-column operations fold, in order, into ONE assignment per column : replace/add set the column to the value, remove sets it to NULL, array_append appends and an RFC 7396 merge merges into whatever the column holds at that point in the sequence. Emitting one assignment per operation lost every write but the last to a repeated column (SQLite keeps the last duplicate assignment). Operations before a column's final replace/add/remove are overwritten and bind no placeholder. Columns appear in first-touched order.

Relation ops (PathSchema.Relation != nil) split off into the result's RelationOps slice; the repository decorator is responsible for emitting the junction SQL bound to the affected owner PKs in the same transaction as the owner UPDATE.

WithChangePredicate also compiles the condition under which the patch's columns change a row (PatchSQLResult.ChangePredicate), for an UPDATE that writes, stamps and counts only the rows it changes.

Operations SQL cannot express are rejected, never skipped: test (E2068), move/copy and nested JSON Pointer paths (E2070). Apply those through the typed document path instead.

type PatchSchema

type PatchSchema struct {
	Resource      string
	AllowedPaths  map[string]*PathSchema
	MaxOperations int
	// contains filtered or unexported fields
}

PatchSchema defines allowed patch operations for a resource.

func GeneratePatchSchema

func GeneratePatchSchema[T any](g *core.SchemaGenerator) (*PatchSchema, error)

GeneratePatchSchema generates a PatchSchema from struct tags on type T.

func GenerateServerPatchSchema

func GenerateServerPatchSchema[T any](g *core.SchemaGenerator) (*PatchSchema, error)

GenerateServerPatchSchema generates the patch schema of the server's own writes: every field GeneratePatchSchema admits, and every field tagged `parse:"server"` — a column only the server sets, such as a credential's fingerprint, which a request body must never reach. A server field the field-name tag hides (`json:"-"`) is addressed by ServerFieldName.

type PatchValidator

type PatchValidator func(op *PatchOperation, subject *core.PolicySubject) error

PatchValidator is a function that validates a patch operation against policy.

type PathSchema

type PathSchema struct {
	AllowedOps []PatchOp
	DataType   core.FieldType
	// SQLType distinguishes declared JSON from native driver-value storage.
	SQLType core.SQLType
	// GoType is the Go type the path's value decodes into (the struct
	// field's type, pointer included). It drives parse-time validation so an
	// accepted operation always applies: numeric range
	// against the exact kind, nullability (only pointer, slice, map and
	// interface fields accept null or remove), array element types, and the
	// shape of struct / map values. nil — hand-built schemas — validates by
	// DataType alone over the widest numeric domain and admits null.
	GoType     reflect.Type
	Validators []core.Validator
	// EnumValues is the path's `enum` allowlist (also a Validator), for
	// schema discovery.
	EnumValues []string
	// Bounds are the path's minlen, maxlen, min and max bounds (also a
	// Validator) and its minitems and maxitems element counts (checked on
	// an array set whole, and by Nullable), for schema discovery.
	Bounds    core.Bounds
	SQLColumn string

	// Relation is non-nil when the path patches an M2M relation rather
	// than a scalar column. When set, BuildPatchSQL emits
	// junction INSERT/DELETE statements into PatchSQLResult.RelationOps
	// instead of touching SQLColumn (which is "" for relation paths).
	// AllowedOps for a relation path is the relation-verb subset
	// (replace / add / remove); RFC 6902's move/copy/test are rejected
	// at validation with E2117.
	Relation *core.RelationSchema
}

PathSchema defines a single patchable path.

func RelationPath

func RelationPath(rel *core.RelationSchema, goType reflect.Type) *PathSchema

RelationPath is the patch path of a relation's membership: replace, add and remove of a slice of target keys (goType), routed to RelationOps.

func (*PathSchema) AllowsOp

func (p *PathSchema) AllowsOp(op PatchOp) bool

AllowsOp checks whether op is in the path's allowed ops list.

func (*PathSchema) ClearedValue

func (p *PathSchema) ClearedValue() any

ClearedValue is what removing the path, or setting it to null, stores: nil (SQL NULL) for pointers, interfaces and untyped paths, and the empty value for a slice or map. Slice and map columns are usually NOT NULL with an empty default, where NULL fails the write, and empty is a valid cleared value for a nullable one too — so clearing empties them on every backend.

func (*PathSchema) Nullable

func (p *PathSchema) Nullable() bool

Nullable reports whether the path accepts null: its Go type can hold null, and null does not clear it to an empty array its least element count refuses. Unknown types (GoType nil) are treated as nullable.

type RawPatchOp

type RawPatchOp struct {
	Op    string `json:"op"`
	Path  string `json:"path"`
	From  string `json:"from,omitempty"`
	Value any    `json:"value,omitempty"`
	// HasValue reports that the operation carried a value member, so an
	// explicit null is told from no value at all. Parse sets it; a caller of
	// ParseOps sets it for a null value — a non-nil Value implies it.
	HasValue bool `json:"-"`
}

RawPatchOp is a decoded patch operation. Used directly by Parser.ParseOps for non-JSON inputs, and internally by Parser.Parse after JSON decoding.

type RelationOwner

type RelationOwner struct {
	Table, Key, Tenant string
}

RelationOwner is the table a relation's owners are rows of.

type RelationPatchOp

type RelationPatchOp struct {
	// Field is the filter-API field name that the patch path resolved
	// to (e.g. "tags" for path "/tags"). Used for error messages and
	// audit logs.
	Field string

	// Schema is the junction descriptor (junction table, source/target
	// columns, optional tenant column).
	Schema *core.RelationSchema

	// Verb is the membership change verb derived from the wire op.
	Verb RelationVerb

	// Values is the list of target IDs the verb applies to. Empty is
	// valid for RelationVerbReplace (clears the relation) but not for
	// add / remove.
	Values []any
}

RelationPatchOp is a parsed junction-membership change extracted from a JSON Patch document. The repository decorator binds these to the owner PKs returned by the owner UPDATE and emits the junction SQL inside the same transaction.

type RelationVerb

type RelationVerb string

RelationVerb identifies how a relation patch op modifies junction membership. The wire-level op name (PatchOpReplace etc.) maps 1:1 to a verb at parse time.

const (
	// RelationVerbReplace is full-diff: the relation becomes exactly the
	// supplied set. Implemented as a junction DELETE for rows whose
	// target is not in the new set, followed by an INSERT … ON CONFLICT
	// DO NOTHING for the supplied targets.
	RelationVerbReplace RelationVerb = "replace"
	// RelationVerbAdd unions the supplied targets into the existing set
	// (junction INSERT … ON CONFLICT DO NOTHING).
	RelationVerbAdd RelationVerb = "add"
	// RelationVerbRemove subtracts the supplied targets from the set
	// (junction DELETE WHERE target IN (…)).
	RelationVerbRemove RelationVerb = "remove"
)

type RenderRelationOpOptions

type RenderRelationOpOptions struct {
	// TenantValue is bound into every junction statement as the value of
	// RelationSchema.TenantColumn. Required when the schema declares a
	// TenantColumn — rendering fails without it unless Unscoped is set
	//. Ignored for unscoped junctions.
	TenantValue any
	// Unscoped deliberately renders a tenant-scoped junction without a
	// tenant predicate. Never set it on a request path.
	Unscoped bool
	// Owner names the owner table, key and tenant column. A many-to-many
	// with a target (RelationSchema.TargetTable) needs it: its inserts
	// select the owner rows and the visible target rows instead of binding
	// raw values, so no pair names a target the request cannot see.
	Owner RelationOwner
	// TargetVisible renders the predicate (starting " AND ", or "") that
	// holds the target rows under alias to those the request may relate,
	// binding values with bind (filter.VisibleRelated). Required with a
	// TargetTable: inserts pair only visible targets, and deletes remove
	// only pairs to them.
	TargetVisible func(alias string, bind func(any) string) (string, error)
}

RenderRelationOpOptions configures RenderRelationOp.

type RenderedRelationStatement

type RenderedRelationStatement struct {
	SQL  string
	Args []any
}

RenderedRelationStatement is one DELETE or INSERT emitted for a relation patch op. The repository decorator runs each statement on the open transaction in slice order; statements within one rendered op are atomic with the owner UPDATE that produced ownerPKs.

func RenderRelationOp

func RenderRelationOp(op RelationPatchOp, dialect dialect.Dialect, ownerPKs []any, opts RenderRelationOpOptions) ([]RenderedRelationStatement, error)

RenderRelationOp turns a parsed RelationPatchOp into the dialect- specific SQL statements that apply the membership change to the junction table for the supplied owner PK set.

The output is a list of {SQL, Args} pairs the caller executes in order on an open transaction. .

Statement shapes:

replace, len(values) > 0:
  DELETE FROM j WHERE source = ANY/IN (pks) AND target NOT IN (vals) [AND tenant = t]
  INSERT INTO j (source, target [, tenant]) VALUES (pk×val) ON CONFLICT DO NOTHING
replace, len(values) == 0:
  DELETE FROM j WHERE source = ANY/IN (pks) [AND tenant = t]                    -- clear
add:
  INSERT INTO j (source, target [, tenant]) VALUES (pk×val) ON CONFLICT DO NOTHING
remove:
  DELETE FROM j WHERE source = ANY/IN (pks) AND target IN (vals) [AND tenant = t]

Cross-product semantics: a patch supplying values [a,b,c] applied to PK set [p1,p2] inserts six rows (p1,a),(p1,b),(p1,c),(p2,a),…,(p2,c). "Replace" diffs per (pk, target) — each PK in ownerPKs gets exactly the supplied value set. Multi-PK patch is allowed but uncommon; the usual call shape is one PK at a time.

type SQLDialect

type SQLDialect interface {
	dialect.Dialect
	MarshalValue(value any, t core.TypeInfo) (any, error)
}

SQLDialect is the dialect surface BuildPatchSQL needs: placeholders and a name for dialect-specific SQL, plus value binding for composite types (a PostgreSQL TEXT[] column takes a Go slice, a SQLite array column takes JSON text). Requiring MarshalValue in the signature makes the wrong binding uncompilable instead of a runtime "malformed array literal". The parse/filter dialects implement it.

type ValueConstraint

type ValueConstraint struct {
	AllowedValues []any
	DeniedValues  []any
	Pattern       string
	Min           *float64
	Max           *float64
	// contains filtered or unexported fields
}

ValueConstraint restricts values for a specific patch path.

func NewValueConstraint

func NewValueConstraint(pattern string, allowed, denied []any, min, max *float64) (*ValueConstraint, error)

NewValueConstraint creates a ValueConstraint and eagerly compiles the regex pattern (if set), returning an error for invalid patterns. Prefer this over direct struct construction to catch regex errors at startup.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL