> For the complete documentation index, see [llms.txt](https://codifi-fdm.gitbook.io/codifi-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://codifi-fdm.gitbook.io/codifi-docs/cross-platform-features/ripple/reference.md).

# Operations Reference

A complete reference of every operator Ripple supports, organized by category. Use this page to look up exact names, arguments, and return types.

***

## Math Operations

| Operation                | Description                      |
| ------------------------ | -------------------------------- |
| `+` (add)                | Add numbers together             |
| `−` (subtract)           | Subtract one number from another |
| `*` (multiply)           | Multiply numbers                 |
| `/` (divide)             | Divide one number by another     |
| `%` (modulo)             | Remainder after division         |
| `round(value, decimals)` | Round to N decimal places        |
| `ceil(value)`            | Round up to nearest integer      |
| `floor(value)`           | Round down to nearest integer    |
| `abs(value)`             | Absolute value (remove negative) |
| `pow(base, exponent)`    | Raise to a power                 |
| `sqrt(value)`            | Square root                      |
| `toNumber(value)`        | Convert text to a number         |
| `isNumeric(value)`       | Check if value is a number       |

***

## Text Operations

| Operation                          | Description                                           |
| ---------------------------------- | ----------------------------------------------------- |
| `concat(...values)`                | Join multiple text values together                    |
| `upper(text)`                      | Convert to UPPERCASE                                  |
| `lower(text)`                      | Convert to lowercase                                  |
| `titleCase(text)`                  | Convert To Title Case                                 |
| `capitalize(text)`                 | Capitalize first letter                               |
| `trim(text)`                       | Remove leading/trailing whitespace                    |
| `substring(text, start, end)`      | Extract portion of text                               |
| `replace(text, find, replacement)` | Replace first occurrence                              |
| `contains(text, search)`           | Check if text includes a word                         |
| `startsWith(text, prefix)`         | Check if text starts with a value                     |
| `endsWith(text, suffix)`           | Check if text ends with a value                       |
| `indexOf(text, search)`            | Find position of text within text                     |
| `length(value)`                    | Count characters in a string **or** items in an array |
| `split(text, separator)`           | Break text into an array                              |
| `join(array, separator)`           | Combine array into text                               |
| `padStart(text, length, char)`     | Pad from the left                                     |
| `padEnd(text, length, char)`       | Pad from the right                                    |

***

## Date Operations

| Operation                      | Description                                    |
| ------------------------------ | ---------------------------------------------- |
| `now()`                        | Current date and time                          |
| `today()`                      | Current date (midnight)                        |
| `dateAdd(date, amount, unit)`  | Add time to a date (days, months, years, etc.) |
| `dateDiff(date1, date2, unit)` | Difference between two dates                   |
| `formatDate(date, format)`     | Format a date (YYYY-MM-DD, MM/DD/YYYY, etc.)   |
| `year(date)`                   | Extract the year                               |
| `month(date)`                  | Extract the month (1–12)                       |
| `day(date)`                    | Extract the day of month                       |
| `toDate(value)`                | Convert a value to a date                      |
| `toUTCDate(value)`             | Convert a value to a UTC date                  |

***

## Logic & Comparison

| Operation                   | Description                                        |
| --------------------------- | -------------------------------------------------- |
| `==` (equals)               | Check if two values are equal                      |
| `!=` (not equals)           | Check if two values are different                  |
| `>` (greater than)          | Check if left is larger                            |
| `>=` (greater or equal)     | Check if left is larger or equal                   |
| `<` (less than)             | Check if left is smaller                           |
| `<=` (less or equal)        | Check if left is smaller or equal                  |
| `and`                       | All conditions must be true                        |
| `or`                        | At least one condition must be true                |
| `!` (not)                   | Reverse a true/false value                         |
| `if(condition, then, else)` | Return different values based on a condition       |
| `isNull(value)`             | Check if value is null/missing                     |
| `isEmpty(value)`            | Check if value is empty (null, "", or empty array) |
| `isNotEmpty(value)`         | Check if value has content                         |
| `coalesce(...values)`       | First non-null value from a list                   |
| `toBoolean(value)`          | Convert a value to true/false                      |
| `toString(value)`           | Convert a value to text                            |

***

## Array Operations

These operators work on arrays returned by `childrenOfType(...)`, `split(...)`, or repeater enumerations.

| Operation                | Description                             |
| ------------------------ | --------------------------------------- |
| `count(array)`           | Number of items in an array             |
| `first(array)`           | First item                              |
| `last(array)`            | Last item                               |
| `atIndex(array, n)`      | Item at position N (zero-based)         |
| `unique(array)`          | Remove duplicates                       |
| `flatten(array)`         | Flatten nested arrays one level         |
| `sort(array)`            | Sort ascending                          |
| `reverse(array)`         | Reverse order                           |
| `sum(array)`             | Sum of numeric values                   |
| `avg(array)`             | Average of numeric values               |
| `min(array)`             | Smallest value                          |
| `max(array)`             | Largest value                           |
| `arrayIsEmpty(array)`    | True if the array has zero items        |
| `arrayIsNotEmpty(array)` | True if the array has at least one item |

***

## Spatial & Geospatial

| Operation                                   | Description                        | Returns                                   |
| ------------------------------------------- | ---------------------------------- | ----------------------------------------- |
| `haversineDistance(lat1, lon1, lat2, lon2)` | Distance between two points        | Meters                                    |
| `pointToLineDistance(point, line)`          | Distance from a point to a line    | Meters                                    |
| `nearestPointOnLine(point, line)`           | Closest point on a line            | Lat/Lon + distance                        |
| `bearing(lat1, lon1, lat2, lon2)`           | Compass direction between points   | Degrees (0–360)                           |
| `midpoint(lat1, lon1, lat2, lon2)`          | Center between two points          | Lat/Lon                                   |
| `lineLength()`                              | Length of a line geometry          | Meters                                    |
| `totalTrackLength()`                        | Sum of point-to-point distances    | Meters                                    |
| `polygonArea()`                             | Area of a polygon                  | Square meters                             |
| `polygonPerimeter()`                        | Perimeter of a polygon             | Meters                                    |
| `pointInPolygon(point, polygon)`            | Is point inside polygon?           | True/False                                |
| `centroid()`                                | Center of all locations            | Lat/Lon                                   |
| `boundingBox()`                             | Min/max extent rectangle           | Coordinates                               |
| `utm` (on a location)                       | UTM conversion of a location       | Object with `zone`, `easting`, `northing` |
| `latitude` / `longitude` (on a location)    | Coordinates of a location point    | Decimal degrees                           |
| `locationIsValid` (on a location)           | GPS coordinates within valid range | True/False                                |
| `locationCount`                             | Number of GPS points on a Record   | Count                                     |
| `validLocationCount`                        | Number of valid GPS points         | Count                                     |

{% hint style="warning" %}
`latitude`, `longitude`, `easting`, `northing`, and `zone` are **properties** on a location or UTM object — read them via dot navigation (e.g., `utm.easting`), not as standalone operators.
{% endhint %}

***

## Aggregation

### Repeater Aggregation

| Operation                                      | Description                      |
| ---------------------------------------------- | -------------------------------- |
| `sumRepeater(section, field)`                  | Sum a field across repeater rows |
| `avgRepeater(section, field)`                  | Average across repeater rows     |
| `minRepeater(section, field)`                  | Minimum across repeater rows     |
| `maxRepeater(section, field)`                  | Maximum across repeater rows     |
| `repeaterCount(section)`                       | Count of repeater rows           |
| `concatRepeater(section, field, separator)`    | Join text from repeater rows     |
| `repeaterFieldAtRow(section, field, rowIndex)` | Get a specific row's value       |

### Child Record Aggregation

| Operation                                         | Description                             |
| ------------------------------------------------- | --------------------------------------- |
| `childrenOfType(archetype)`                       | Array of child Records of an archetype  |
| `countChildrenWhere(archetype, field, condition)` | Count children matching a condition     |
| `sumChildren(archetype, field)`                   | Sum a field across direct child Records |
| `hasChildOfType(archetype)`                       | Check if children of an archetype exist |

{% hint style="warning" %}
There is **no bare `countChildren`** operator. To count all children of an archetype, use `count(childrenOfType("Feature"))` or `countChildrenWhere(...)` with a condition that matches everything.
{% endhint %}

***

## Record Navigation & Properties

| Property                            | Description                                  |
| ----------------------------------- | -------------------------------------------- |
| `parent`                            | The parent Record                            |
| `parents`                           | All parents (for many-to-many relationships) |
| `children`                          | All direct child Records                     |
| `childrenOfType(name)`              | Direct children of a specific archetype      |
| `siblings`                          | Records sharing the same parent              |
| `siblingCount`                      | Number of siblings                           |
| `allAncestors`                      | All Records up to root (max 10 levels)       |
| `allDescendants`                    | All Records down (max 10 levels)             |
| `ancestorCount` / `descendantCount` | Counts of the above                          |
| `isRoot`                            | True if the Record has no parent             |
| `depth`                             | Depth in the hierarchy (root = 0)            |
| `recordType`                        | The Record's archetype name                  |
| `titleFieldValue`                   | Display value of the title field             |
| `assigneeName`                      | Name of the assigned user                    |
| `startDate` / `endDate`             | Record-level dates                           |
| `hasLocation`                       | Whether the Record has GPS data              |
| `recordsCount` (on a Project)       | Total Records in the Project                 |

***

## Field Metadata (on a field reference)

When you reference a specific field by label (e.g. `getFieldByLabel("Soil Type")`), these properties are available on the field instance.

| Property                                 | Description                                       |
| ---------------------------------------- | ------------------------------------------------- |
| `value`                                  | The field's current value                         |
| `rawValue`                               | The field's raw value (before display formatting) |
| `numericValue`                           | Numeric coercion of the value                     |
| `selectedOptions`                        | Selected entries for dropdowns / multi-selects    |
| `fieldStartDate` / `fieldEndDate`        | The two halves of a Date Range field              |
| `isDateRange`                            | True if the field is configured as a date range   |
| `isMultiline`                            | True if the field is multi-line text              |
| `allowsMultiple`                         | True if the field allows multiple values          |
| `isRequired`                             | True if the field is required                     |
| `isPending`                              | Required AND still empty                          |
| `isVisible`                              | True if visibility rules currently show the field |
| `label` / `fieldType` / `fieldTypeName`  | Field metadata                                    |
| `isTitle`                                | True if this is the Record's title field          |
| `options`                                | Available options for dropdowns / radios          |
| `decimalCount` / `maxLength`             | Numeric and text constraints                      |
| `isInRepeater` / `rowIndex` / `rowCount` | Repeater context (when inside a repeater)         |
| `sectionLabel`                           | Label of the field's containing section           |

***

## Media & Completion

| Property                                                     | Description                                           |
| ------------------------------------------------------------ | ----------------------------------------------------- |
| `hasMedia` / `mediaCount`                                    | Whether/how many attachments exist                    |
| `photoCount` / `videoCount` / `audioCount` / `documentCount` | Counts by media type                                  |
| `totalFileSize`                                              | Combined size of all attachments                      |
| `countMediasByExtension(ext)`                                | Files of a specific extension                         |
| `hasMediaWithExtension(ext)`                                 | Whether at least one file of a given extension exists |
| `gpsLatitude` / `gpsLongitude` (on a media)                  | EXIF coordinates                                      |
| `dateTaken` (on a media)                                     | EXIF capture date                                     |
| `mediaSubTypeName`                                           | Name of the media's subtype                           |
| `mediaType`                                                  | Type (photo / video / audio / document)               |
| `mediaIsValid`                                               | True if the media file is valid                       |
| `completionPercent`                                          | 0–100 percent of required fields filled               |
| `requiredFieldCount` / `completedFieldCount`                 | Counts of required / completed fields                 |

***

## Tips & Best Practices

* ✓ **User input always wins.** If a user types a value into a calculated field, their value is kept. The formula only fills empty fields.
* ✓ **Keep trigger fields visible.** A field that controls visibility of other sections should be in an always-visible section. If the trigger field itself is hidden, the fields it controls can't respond to changes.
* ✓ **Don't rename fields referenced by formulas.** Formulas look up fields by their label (display name). If you rename "Site Type" to "Resource Type", any formula referencing "Site Type" will silently stop working. Update formulas when renaming fields.
* ✓ **Use "Multi-component" for dual visibility.** When recording sites that are both prehistoric and historic, use a multi-component option that shows both sets of fields, rather than forcing users to choose one.
* ✓ **Test with empty data.** Formulas run when fields are empty. Make sure your formulas handle empty/null values gracefully. Use `isEmpty()` to avoid showing partial results before the user has entered data.
* ✓ **Cascading formulas are automatic.** If Formula A depends on Formula B, Ripple automatically evaluates them in the right order.
* ✓ **Spatial formulas need GPS data.** Distance, area, and coordinate formulas only work when the Record has location data attached.
* ✓ **Visibility hides, not deletes.** When a visibility formula hides a field or section, the data is preserved — it's just not shown.
* ✓ **Aggregations update in real-time.** Add a child Record and parent counts/sums update automatically. No manual refresh needed.
* ✓ **Formulas work offline.** On the mobile app, all Ripple formulas evaluate locally on your device. You don't need internet connectivity for calculated fields or visibility rules to work in the field.

***

## For Formula Authors: JsonLogic Notes

Ripple formulas are stored as [JsonLogic](https://jsonlogic.com) expressions. Most users never see this — admins build formulas in the Composition editor's UI. If you're authoring formulas as raw JsonLogic, two gotchas to know:

* **Refer to the current Record with `{"var": ""}`** — not `{"var": "current"}`. The empty-string variant is the working convention; older docs may show the alternative, but it isn't supported.
* **Don't bake repeater section IDs into formulas.** Section IDs can be regenerated when an admin re-saves the archetype. Reference repeaters by **label** (e.g. `repeaterCount("Artifacts")`) so formulas survive section edits.
* **For Date Range fields, use `fieldStartDate` / `fieldEndDate`**, not `value`. The `.value` of a Date Range is a `{StartDate, EndDate}` object that won't feed correctly into `dateDiff` or `dateAdd`.
* **`hasLocation` and `locations` accessors** work on archetype Records. They don't work directly on Project Details (PD) because PD has no recordTypeId. Use them on archetypes when mirroring lat/long to read-only fields.

***

## See Also

* [Value Formulas](/codifi-docs/cross-platform-features/ripple/value-formulas.md) — math, text, dates, lookups
* [Visibility Formulas](/codifi-docs/cross-platform-features/ripple/visibility-formulas.md) — show/hide rules
* [Spatial Formulas](/codifi-docs/cross-platform-features/ripple/spatial-formulas.md) — distance, area, perimeter, coordinates
* [Aggregation Formulas](/codifi-docs/cross-platform-features/ripple/aggregation-formulas.md) — sum, count, concat across rows or children
* [Media & Completion](/codifi-docs/cross-platform-features/ripple/media-and-completion.md) — attachment awareness and form progress
* [Real-World Examples](/codifi-docs/cross-platform-features/ripple/examples.md) — full configurations for common CRM patterns
