# `PB.Validate`
[🔗](https://github.com/hansihe/pb_ex/blob/v0.2.0/pb_validate/lib/pb/validate.ex#L1)

Runtime protovalidate validation.

Validation accepts the same public message term shape as `PB.encode/4`.
Canonical maps, represented structs, identity oneofs, unwrapped messages, and
adapted values are projected one message layer at a time before field rules,
message rules, and CEL expressions read protobuf fields.

Validation rule failures return `{:error, %PB.Validate.Error{}}`. Unknown
messages, message-name metadata mismatches, values that do not match the
message shape, and projection failures return the `PB.Error` struct
`PB.encode/4` would (`PB.SchemaError` or `PB.ValueError`, with
`operation: :validate`); a CEL rule that fails to evaluate returns
`CEL.Error`. Those are errors rather than protovalidate violations, so
they are not `PB.Validate.Error`s.

Schemas may be supplied either as a compiled schema map or as a module that
`use PB.Schema`, and must be compiled with this module as a plugin, which
compiles the protovalidate rules in the schema's descriptor options:

    schema = PB.compile(descriptor_set, plugins: [PB.Validate])

    defmodule MyApp.Schema do
      use PB.Schema, descriptor: "priv/proto/schema.binpb", plugins: [PB.Validate]
    end

Compiling raises `PB.Validate.CompileError` for rules that are not valid for
the schema, and `PB.SchemaError` for a schema whose rules can't be read, as
its descriptor set lacks `buf/validate/validate.proto`.

# `result`

```elixir
@type result() :: :ok | {:error, PB.Validate.Error.t() | PB.Error.t() | CEL.Error.t()}
```

# `compile`

```elixir
@spec compile(
  PB.schema(),
  keyword()
) :: PB.schema()
```

Compiles the protovalidate rules of a prepared `schema` into it.

This is the `PB.Schema.Plugin` callback; pass `plugins: [PB.Validate]` to
`PB.compile/2` or `use PB.Schema` rather than calling it. It takes no options.

# `schema_functions`

```elixir
@spec schema_functions(keyword()) :: Macro.t()
```

Returns the functions `use PB.Schema` adds to a schema module compiled with
this plugin: `validate/2,3` and `validate!/2,3`, which call `validate/4` and
`validate!/4` with the module's schema.

# `to_proto_violations`

```elixir
@spec to_proto_violations(
  validation_result()
  | PB.Validate.Error.t()
  | [PB.Validate.Violation.t() | map()]
) :: %{violations: [map()]}
```

Converts validation violations to the canonical `buf.validate.Violations`
protobuf field shape.

# `validate`

```elixir
@spec validate(term(), PB.schema_source(), PB.message_name(), keyword()) :: result()
```

Validates `data` as `message_name` using `schema`.

Rule failures return `{:error, %PB.Validate.Error{}}`. Option failures return
`{:error, %PB.OptionError{}}`, and unknown messages or values that do not
match the message shape the `PB.Error` struct `PB.encode/4` would. A CEL rule
that fails to evaluate returns `{:error, %CEL.Error{}}`. Raises
`ArgumentError` if `schema` was not compiled with `plugins: [PB.Validate]`.

Accepted options:

  * `:context` - a keyword list or map of context values, currently only
    `:now` (as below).
  * `:now` - timestamp used for CEL `now`: unix nanoseconds, `DateTime`, or
    a CEL timestamp tuple `{:timestamp, unix_nanoseconds}`.

# `validate!`

```elixir
@spec validate!(term(), PB.schema_source(), PB.message_name(), keyword()) :: :ok
```

Validates `data` as `message_name` using `schema`, raising on validation or
option failure.

See `validate/4` for accepted options.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
