# Functions overview

Functions are a core building block in DataPrime. They provide the ability to transform, compute, and manipulate data within queries, supporting everything from simple type conversions to complex data pipelines.

Most DataPrime functions support two interchangeable syntaxes for calling functions:

- Function notation: traditional nested function calls
- Method notation: a flat, chained syntax similar to object-oriented programming

Both styles are fully equivalent in behavior. Users are free to choose the option that best suits the preferred query style or readability preference.

| Function Notation                                               | Method Notation                                                  |
| --------------------------------------------------------------- | ---------------------------------------------------------------- |
| `dataprime <function-name>(<value>, args...): <return type> `   | `dataprime <value>.<function-name>(args...): <return type> `     |
| **Example with `startsWith` function:**                         |                                                                  |
| `dataprime startsWith(value: string, prefix: string): boolean ` | `dataprime (value: string).startsWith(prefix: string): boolean ` |

While function notation uses nested calls, method notation offers a flatter, more readable structure—especially when chaining multiple operations.

## Example of notation differences

A user may want to query a specific username or collection of usernames, but it may be necessary to use multiple functions to get the correct match.

1. usernames may be padded with spaces, so the `trim` function is used to remove the white space.
1. The `toLowerCase` function will make the query non-case sensitive.
1. The desired username(s) begin with the substring `production-`, requiring the `startsWith` function.

Depending on how the rest of the query is constructed, function notation or method notation may be preffered. However, **these two approaches will work equivalently**.

| Function Notation                                        | Method Notation                                           |
| -------------------------------------------------------- | --------------------------------------------------------- |
| `startsWith(toLowerCase(trim(username)), 'production-')` | `username.trim().toLowerCase().startsWith('production-')` |

In both functions:

1. `trim(username)` runs first.
1. The result of `trim(username)` is passed to `toLowerCase`.
1. The result of `toLowerCase(trim(username))` is then passed to `startsWith`, where we check that the username starts with the substring `production-`

In both styles, the data flows the same way: **`username` → `trim` → `toLowerCase` → `startsWith`**. The only difference is the structure: nested in function notation, chained in method notation.

Both expressions are logically equivalent:

```dataprime
startsWith(toLowerCase(trim(username)),'production-') == username.trim().toLowerCase().startsWith('production-')
```

This expression will evaluate to `true`.

### Why choose one syntax over another?

- Choose function notation for writing short, standalone calls
- Choose method notation for chaining multiple operations on the same value and a clean, linear structure
