> For the complete documentation index, see [llms.txt](https://radoslaw-medryk.gitbook.io/verifica/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://radoslaw-medryk.gitbook.io/verifica/predicates/custom-predicates.md).

# Custom Predicates

Predicates are functions used by verifica to decide if value is matching some validation rule, and if no, then what is the error. To be valid a `Predicate` , functions need to follow certain format:

```typescript
function isSmallNumber(verificable): VerificaError | VerificaError[] | undefined {
    // perform all necessary checks here,
    
    // return VerificaError or array of those errors if invalid,
    // return undefined/nothing otherwise,
    
    // ot throw VerificaException with provided errors.
}
```

* They need to take one argument which will be `Verificable` object to be checked.
* They need to return: `VerificaError`, an array of `VerificaError` objects, or undefined / nothing.
* They can also throw `VerificaException` with errors, that will be treated the same by verifica as returning `VerificaError` object(s).

## Patterns

In general, fulfilling the requirements specified above is enough for a function to be considered as a `Predicate` . There is a set of useful patterns however, that can make writing `Predicate` functions easier. Those patterns are listed below.

#### Using rawValue() function:

Using `rawValue()` function we can get raw value behind representing it `Verificable` object. We can do our necessary tests directly on it, and then return error / no error based on that.

```typescript
const { rawValue, makeError } = require("verifica");

function isSmallNumber(verificable) {
    // get raw value to be checked:
    const value = rawValue(verificable);
    
    // return error if not matching:
    if (!(typeof value === "number") || value < 0 || value > 10) {
        return makeError(verificable, {
            type: "isSmallNumber",
        });
    }
    
    // return nothing if OK.
}
```

And let's try it out:

```typescript
const { asVerificable, isValid, getErrors } = require("verifica");

const value = 14;
const verificable = asVerificable(value);

isValid(verificable, isSmallNumber); // false
getErrors(verificable, isSmallNumber);
// [{ type: "isSmallnumber", path: [] }]
```

#### Using ensure() function:

Instead of using `rawValue()` , we can also call `ensure()` with some prerequisite condition predicate, like `isNumber` here. If it throws `VerificaException`, the validation will be considered not passed with errors coming from thrown `VerificaException` . If it doesn't throw, we already now `value` is a number, so we only need to check for other custom conditions (like `< 0`, `> 10` in the example) and decide there if error / no error should be returned.

```typescript
const { ensure, isNumber, makeError } = require("verifica");

function isSmallNumber(verificable) {
    // get value ensuring first that it is a number:
    const value = ensure(verificable, isNumber);
    // since ensure didn't throw, we know value is a number here.
    // if ensure would throw VerificaException with errors,
    // it will be treated as returning those error(s).
    
    
    // return error if not matching:
    if (value < 0 || value > 10) {
        return makeError(verificable, {
            type: "isSmallNumber",
        });
    }
    
    // return nothing if OK.
}
```

And let's try it out:

```typescript
const { asVerificable, isValid, getErrors } = require("verifica");

const value = 14;
const verificable = asVerificable(value);

isValid(verificable, isSmallNumber); // false
getErrors(verificable, isSmallNumber);
// [{ type: "isSmallnumber", path: [] }]
```

#### Using multiple ensure() functions:

`ensure()` function can be called multiple times in the same `Predicate` function, e.g. checking if properties of an object matches required conditions as well. If any of those calls throw an `VerificaException`, the whole predicate is considered as not matching, with error(s) taken from the `VerificaException`.

```typescript
const { ensure, isObject, isString, isNumber } = require("verifica");

// We expect object in this format:
// {
//     name: string;
//     address: {
//         street: string;
//         zipCode: number;
//     }
// }

function isUser(verificable) {
    ensure(verificable, isObject);
    ensure(verificable.name, isString);
    
    ensure(verificable.address, isObject);
    ensure(verificable.address.street, isString);
    ensure(verificable.address.zipCode, isNumber);
    
    // If none of above ensure threw an exception, we consider object valid.
    // return nothing if OK.
}
```

And let's try it out:

```typescript
const { asVerificable, isValid, getErrors } = require("verifica");

const value = {
    name: "john Smith",
    address: {
        street: null,
        zipCode: null,
    }
};
const verificable = asVerificable(value);

isValid(verificable, isUser); // false
getErrors(verificable, isUser);
// [{ type: "isString", path: ["address", "street"] }]
```

#### Using VerificaChunk:

`VerificaChunk` can be also used to perform multiple checks on multiple values at the same time.

The difference between using `VerificaChunk` and just multiple `ensure()` calls in a row is that `VerificaChunk` will perform all the checks when `chunk.ensureAll()` is called, and throw `VerificaException` containing all aggregated errors from all the checks. Calling `ensure()` multiple times will throw on first error and only that error will be returned.

```typescript
const { VerificaChunk, isObject, isNumber, isString } = require("verifica");

// We expect object in this format:
// {
//     id: number;
//     name: string;
//     price: number;
// }

function isProduct(verificable) {
    const chunk = new VerificaChunk();
    
    chunk.add(verificable, isObject);
    chunk.add(verificable.id, isNumber);
    chunk.add(verificable.name, isString);
    chunk.add(verificable.price, isNumber);
    
    chunk.ensureAll();
    
    // If chunk.ensureAll() didn't threw an exception, we consider object valid.
    // return nothing if OK.
}
```

And let's try it out:

```typescript
const { asVerificable, isValid, getErrors } = require("verifica");

const value = {
    id: ["a", "b"],
    name: null,
    price: 88,
};
const verificable = asVerificable(value);

isValid(verificable, isProduct); // false
getErrors(verificable, isProduct);
// [
//     { type: "isNumber", path: ["id"] },
//     { type: "isString", path: ["name"] }
// ]
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://radoslaw-medryk.gitbook.io/verifica/predicates/custom-predicates.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
