> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# Functions

Use SurrealDB built-in functions in Surqlize queries, as typed methods on fields for strings, arrays, numbers, dates, options, and records, or as standalone functions and families such as count, math, time, crypto, and vector, plus db.value().

Surqlize wraps the SurrealDB [function library](/docs/reference/query-language/functions/database-functions.md) in two forms. **Type-specific methods** are called on the fields of a record, for example `user.name.first.uppercase()`. **Standalone functions**, such as `count()` and `math.sum()`, are imported from `surqlize` and take their inputs as arguments. Both can be used in `where()` and `return()`, and each call is typed with the type of its result.

Each method maps to the SurrealQL function of the same name, so `user.name.first.uppercase()` is `string::uppercase()`. Your editor lists the methods available for each field type, and this page covers the common ones.

The examples on this page use the schema below, with `db` created as described in [connections](/docs/libraries/surqlize-typescript/connections.md).

```ts title="Example schema"
import { edge, orm, t, table } from "surqlize";

const user = table("user", {
    name: t.object({ first: t.string(), last: t.string() }),
    email: t.string(),
    age: t.number(),
    bio: t.option(t.string()),
    tags: t.array(t.string()).default([]),
    created: t.date().default(() => new Date()),
});

const post = table("post", {
    title: t.string(),
    tags: t.array(t.string()).default([]),
    author: t.record("user"),
    created: t.date().default(() => new Date()),
});

const authored = edge("user", "authored", "post", { created: t.date() });

const db = orm(surreal, user, post, authored);
```

```ts title="Example data"
import { RecordId } from "surrealdb";

await db.create("user", "ada").content({
    name: { first: "Ada", last: "Lovelace" },
    email: "ada@example.com",
    age: 36,
    tags: ["typescript", "surreal"],
});
await db.create("user", "alan").content({
    name: { first: "Alan", last: "Turing" },
    email: "alan@example.com",
    age: 41,
    bio: "Mathematician",
});
await db.create("post", "hello").content({
    title: "Hello, world",
    tags: ["intro", "surreal"],
    author: new RecordId("user", "ada"),
});
await db.create("post", "graphs").content({
    title: "Hello graphs",
    tags: ["graph"],
    author: new RecordId("user", "alan"),
});
await db.relate("authored", new RecordId("user", "ada"), new RecordId("post", "hello")).content({
    created: new Date(),
});
```

## String functions

```ts title="String methods in a filter"
db.select("user").where((user) => user.email.startsWith("admin@"));
db.select("user").where((user) => user.name.first.endsWith("a"));
db.select("user").where((user) => user.email.contains("@example.com"));
db.select("user").where((user) => user.email.isEmail());
```

```ts title="String methods in a projection"
const rows = await db.select("user").return((user) => ({
    fullName: user.name.first.join(" ", user.name.last),
    nameLength: user.name.first.len(),
    upper: user.name.first.uppercase(),
    lower: user.email.lowercase(),
    slug: user.name.first.slug(),
    words: user.name.first.words(),
    replaced: user.email.replace("@example.com", "@new.com"),
    parts: user.email.split("@"),
}));
```

Other string methods include `capitalize`, `trim`, `repeat`, `slice`, `reverse`, and `matches`, the distance functions (`distanceLevenshtein`, `distanceHamming`, and others), the similarity functions (`similarityJaro`, `similarityFuzzy`, and others), the HTML functions (`htmlEncode`, `htmlSanitize`), the validators (`isUrl`, `isDomain`, `isUuid`, `isIp`, and others), and the semantic version functions (`isSemver`, `semverMajor`, `semverCompare`, and others).

## Array functions

Array fields have membership checks that map to the SurrealQL operators:

```ts title="Array conditions"
db.select("user").where((user) => user.tags.contains("typescript"));
db.select("user").where((user) => user.tags.containsAll(["javascript", "typescript"]));
db.select("user").where((user) => user.tags.containsAny(["rust", "go"]));
db.select("user").where((user) => user.tags.containsNone(["php", "perl"]));
db.select("user").where((user) => user.tags.anyInside(["typescript", "rust"]));
db.select("user").where((user) => user.tags.isEmpty());
```

The methods `containsNot`, `allInside`, and `noneInside` are also available.

They also have functions that return values:

```ts title="Array values"
const rows = await db.select("post").return((post) => ({
    title: post.title,
    firstTag: post.tags.first(),
    lastTag: post.tags.last(),
    tagCount: post.tags.len(),
    sorted: post.tags.sort(),
    unique: post.tags.distinct(),
    upper: post.tags.map((tag) => tag.uppercase()),
}));
```

Array methods that take an element, `append`, `prepend`, `push`, `add`, `insert`, `fill` and `findIndex`, take a plain value of the element type. Surqlize wraps the value for you, so there is no need for [`db.value()`](#literal-values-in-expressions). A value of the wrong type is a compile error. `union`, `difference` and `intersect` take the other array, either as a plain array or wrapped with `db.value()`. A method that returns an array gives a new array in the result and leaves the stored record unchanged.

```ts title="Array methods that take a value"
const rows = await db.select("post").return((post) => ({
    withExtra: post.tags.append("extra"),
    withoutFirst: post.tags.remove(0),
    merged: post.tags.union(["extra"]),
}));
```

## Number and date functions

```ts title="Number methods"
const rows = await db.select("user").return((user) => ({
    rounded: user.age.round(),
    ceiling: user.age.ceil(),
    floored: user.age.floor(),
    squareRoot: user.age.sqrt(),
    squared: user.age.pow(2),
    fixed: user.age.fixed(2),
    clamped: user.age.clamp(0, 100),
}));
```

Number fields also have the trigonometric and logarithmic functions, such as `sin`, `cos`, `tan`, `ln`, `log10`, and `log2`, as well as `abs`, `sign`, and `lerp`.

```ts title="Date methods"
const rows = await db.select("user").return((user) => ({
    year: user.created.year(),
    month: user.created.month(),
    day: user.created.day(),
    weekDay: user.created.wday(),
    unix: user.created.unix(),
    formatted: user.created.format("%Y-%m-%d"),
}));
```

Date fields also have `hour`, `minute`, `second`, `week`, `yday`, `millis`, and `isLeapYear`.

## Option functions

A field of type `t.option()` has helpers for the case where the value is missing.

| Method | Result |
| ------ | ------ |
| `unwrapOr(fallback)` | The value, or the fallback when it is `NONE`. The result is not optional. |
| `isNone()`, `isSome()` | Whether the value is absent or present. |
| `isSomeAnd(callback)` | Whether the value is present and the callback's condition holds. |
| `map(callback)` | The callback applied to the value when it is present, and `NONE` when it is not. The result is optional. |
| `unwrap()` | Treats the value as its inner type, so that you can call the inner type's methods. |

```ts title="Work with optional fields"
const rows = await db.select("user").return((user) => ({
    name: user.name,
    bio: user.bio.unwrapOr("No bio"),
    hasBio: user.bio.isSome(),
    bioLength: user.bio.map((bio) => bio.len()),
}));

const withLongBio = await db
    .select("user")
    .where((user) => user.bio.isSomeAnd((bio) => bio.len().gt(100)));
```

`unwrap()` changes the type and nothing else: the query is the same, and SurrealDB still sees a value that may be `NONE`. A function called on `NONE` makes the query fail, so use `unwrap()` only where the value is known to be present, for example after an `isSome()` condition. Use `unwrapOr()` otherwise.

```ts title="Unwrap a value that is present"
const lengths = await db
    .select("user")
    .where((user) => user.bio.isSome())
    .return((user) => ({
        name: user.name,
        bioLength: user.bio.unwrap().len(),
    }));
```

## Record functions

A record link can run a nested query with `.select()`, as described in [querying](/docs/libraries/surqlize-typescript/querying.md). The nested query returns an array of records for each result. Add `.only()` when the link points to a single record.

```ts title="Select the record a link points to"
const rows = await db.select("post").return((post) => ({
    title: post.title,
    author: post.author.select().only().return((author) => ({ name: author.name })),
}));
```

Record links can also start [graph traversals](/docs/libraries/surqlize-typescript/edges-and-graph.md).

## Standalone functions

Standalone functions are not called on a field. A function that takes values reads its query context from its first value, so you pass fields of the current record as arguments. A function without arguments, or a constant, needs a field or record from the callback to supply that context.

```ts title="Standalone functions"
import { count, crypto, math, not, parse, time } from "surqlize";

const stats = await db
    .select("user")
    .groupAll()
    .return((user) => ({
        total: count(user),
        adults: count(user, user.age.gte(18)),
        averageAge: math.mean(user.age),
    }));

const rows = await db.select("user").return((user) => ({
    now: time.now(user),
    emailHash: crypto.sha256(user.email),
    emailDomain: parse.emailHost(user.email),
    pi: math.pi(user),
}));

const minors = await db.select("user").where((user) => not(user.age.gte(18)));
```

`time.now(user)` and `math.pi(user)` take `user` only to supply the context. `count(user)` counts the records of a [grouped](/docs/libraries/surqlize-typescript/querying.md) select, and a second argument counts only the records for which it is true.

`count()`, `not()`, and `sleep()` are functions. The other standalone functions are grouped in families, which are objects of functions: `math`, `time`, `crypto`, `rand`, `duration`, `type_`, `encoding`, `geo`, `http`, `meta`, `object`, `parse`, `search`, `session`, `set_`, `value`, `vector`, and `bytes`. The names `type_` and `set_` carry a trailing underscore. Surqlize also exports the `and()` and `or()` condition combiners described in [querying](/docs/libraries/surqlize-typescript/querying.md).

## Literal values in expressions

`db.value()` wraps a JavaScript value so that it can be passed to a function or used at the start of a traversal. A `RecordId` keeps its table type.

```ts title="Wrap a value"
import { RecordId } from "surrealdb";

const queryVector = db.value([0.1, 0.2, 0.3]);
const startingPoint = db.value(new RecordId("user", "ada")).out("authored");
```

## Next steps

- [Search, vector, and geometry](/docs/libraries/surqlize-typescript/search-vector-geometry.md) - Full-text matching, vector similarity, and distance between points.

- [Custom functions and APIs](/docs/libraries/surqlize-typescript/custom-functions-and-apis.md) - Call functions and API endpoints that you defined in the database.
