# Scripting

## Introduction

The Medable platform offers a JavaScript API for developers to create, read, update, and delete cortex objects; query and aggregate data; send custom notifications; perform callouts; console and debug logging; create object triggers; run scheduled jobs; create custom API routes and more.

All scripts run synchronously. There are no callbacks or timers and as such no implementation of functions such as `setInterval`, `setTimeout` or `setImmediate`. For example, a route script employing an HTTP callout might look like the following.

```javascript
import http from 'http';

try {
  const response = http.get('https://www.example.com/service?json');
  return JSON.parse(response.body);  
} catch(err) {
    // handle me
}
```

## Environment Notes

### Compatibility

The Javascript engine is `ECMAScript 5/5.1` compliant. You can also use many `ES2015` features and some decorators. The following babel plugins are enabled for that reason.

```
babel-plugin-check-es2015-constants
babel-plugin-transform-decorators-legacy
babel-plugin-transform-class-properties
babel-plugin-transform-regenerator
babel-plugin-transform-es2015-arrow-functions
babel-plugin-transform-es2015-block-scoped-functions
babel-plugin-transform-es2015-block-scoping
babel-plugin-transform-es2015-classes
babel-plugin-transform-es2015-computed-properties
babel-plugin-transform-es2015-duplicate-keys
babel-plugin-transform-es2015-function-name
babel-plugin-transform-es2015-literals
babel-plugin-transform-es2015-modules-commonjs
babel-plugin-transform-es2015-object-super
babel-plugin-transform-es2015-parameters
babel-plugin-transform-es2015-shorthand-properties
babel-plugin-transform-es2015-spread
babel-plugin-transform-es2015-template-literals
babel-plugin-transform-es2015-destructuring
babel-plugin-transform-es2015-for-of
babel-plugin-transform-es2015-typeof-symbol
babel-plugin-transform-object-rest-spread
```

### Decorators

The following `decorators` are built-in and can be imported using the `decorators-{decoratorName}` convention like in this example: `autobind, decorate, deprecate, enumerable, extendDescriptor, lazyInitialize, nonconfigurable, nonenumerable, override, readonly`

```javascript
import autobind from 'decorators-autobind';
import readonly from 'decorators-readonly';

class Eye {   

    @readonly
    pie = 'pie'; // initializable properties support.

    @autobind
    apple() {
        return this.pie;
    }

    orange = () => this.pie; // bound functions support.
}

const eye = new Eye();

eye.apple.call(null); // 'pie' returned even though bound to null.
eye.orange.call(null); // 'pie' returned even though bound to null.
eye.pie = 'not allowed'; // throws
```

### Modules

Module loading is available via CommonJS; Standard and custom modules are loaded using `require` and defined using `module.exports`. Imports and exports are also supported.

For example, a module exported as `c_utils`, defined as:

```javascript
import _  from 'underscore';

export default {

  dateToAge: function(birthDate) {
    if (!_.isDate(birthDate)) return 0;

    const today = new Date(),
          m = today.getMonth() - birthDate.getMonth();

    let age = today.getFullYear() - birthDate.getFullYear();

    if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
      age--;
    }
    return age;
  }
};
```

might be loaded and used in a route as follows:

```javascript
import utils from 'c_utils';

const me = org.objects.Accounts
  .find({
    _id: script.principal._id
  })
  .paths('dob')
  .next();

return utils.dateToAge(new Date(me.dob));
```

All scripts run in strict mode. For triggers, jobs and routes the entry point to the script is called main, which can be seen in script stack traces. In order to get meaningful stack traces, it's good practice to name all functions.

Stack traces are available for debugging via the Error object's `trace` property or the `getCurrentStackTrace` global function. A stack trace is also provided with calls to the `logger` or `console` modules.

The `console`, `consts`, `org` and `script` auto-globals are always guaranteed to be available, though console printing only works on the development servers.

### --

### InsertOperation

Operation defaults are bypassCreateAcl(false), dryRun(false), grant(null), lean(true), skipAcl(false).

bypassCreateAcl(bool = true)\
dryRun(bool = true)\
execute()\
grant(level)\
lean(bool = true)\
locale(identifier)\
skipAcl(bool = true)JavaScript

```
const Items = org.objects.c_items;

const _id = Items.insertOne({c_key: 'unique key'}).execute();

return Items.find({_id: _id}).paths('c_key').next();
```

**InsertOperation.bypassCreateAcl(bool = true)**

Skips createAcl checks.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**InsertOperation.dryRun(bool = true)**

The operation performs a dry run. Though no documents are inserted, before triggers are called.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**InsertOperation.execute()**

Executes the operation.

**Returns**

ObjectID|Object If the lean option is turned off, the inserted document is returned. When true, only the inserted identifier is returned.

**InsertOperation.grant(level)**

Sets the grant level for the operation.

**Arguments**

* `level` (Number)

**Returns**

this

**InsertOperation.lean(bool = true)**

On by default, turning off this option reads the entire inserted document after execution.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**InsertOperation.locale(identifier)**

Specifies the locale of the operation for any localized strings.

**Arguments**

* `identifier` (String) The locale identifier, which consists of a 2 or 3 letter language tag optionally followed by a region separated by `_`. For example, `en`, `en_US`, `en_UK`, etc.

**Returns**

this

**InsertOperation.skipAcl(bool = true)**

Skips acl checks.

**Arguments**

* `bool` (Boolean)

**Returns**

this

### UpdateOperation

Operation defaults are dryRun(false), grant(null), lean(true), skipAcl(false).

```
const Items = org.objects.c_items;

const _id = Items.updateOne({c_key: 'unique key'}, {c_key: 'very unique'})
  .skipAcl()
  .grant(consts.accessLevels.update)  
  .execute();

return Items.find({_id: _id}).paths('c_key').next();
```

**UpdateOperation.dryRun(bool = true)**

The operation performs a dry run. Though no documents are updated, before triggers are called.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**UpdateOperation.execute()**

Executes the operation.

**Returns**

ObjectID|Object If the lean option is turned off, the entire updated document is returned. When true, only the identifier is returned.

**UpdateOperation.grant(level)**

Sets the grant level for the operation.

**Arguments**

* `level` (Number)

**Returns**

this

**UpdateOperation.lean(bool = true)**

True by default, disabling this option reads and returns the entire updated document after execution. `"modified"` may also be used to return an object containing just the modified properties. Otherwise, simply the `_id` of the updated document is returned.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**UpdateOperation.locale(identifier)**

Specifies the locale of the operation for any localized strings.

**Arguments**

* `identifier` (String) The locale identifier, which consists of a 2 or 3 letter language tag optionally followed by a region separated by `_`. For example, `en`, `en_US`, `en_UK`, etc.

**Returns**

this

**UpdateOperation.merge(bool)**

Enabling this option allows for an update operation on an array to include elements with and without identifiers. Elements with identifiers will update the existing array elements while those without identifiers will be pushed into the array as new elements. If disabled, and the update operation includes a mix of elements with and without identifiers, a `kInvalidArgument` will be returned with the reason "Pushed document has an \_id and/or updated document is missing an \_id."

**Arguments**

* `bool` (Boolean)

**Returns**

this

**UpdateOperation.pathDelete(path = null)**

Deletes a single property or array value using the current cursor options. Passing a path argument overwrites the `pathPrefix()` option. For example, `org.objects.c_object.updateOne({_id: _id}).pathDelete("c_docs.5a2c44f836412438e4c372c2.c_array.bar");` removes "bar" from the c\_array string array in the c\_docs document array.

**Arguments**

* `path` (String) Optional. Overrides `pathPrefix()`.

**Returns**

Object

**UpdateOperation.pathPrefix(path = null)**

Sets or removes the operation path prefix. When a prefix is present the operation can target documents in a write-through list or nested document array. For example, `c_parent.updateOne({_id: parentId}, {$push: [{c_name: 'new child'}]}).pathPrefix('c_children').execute()` creates a new c\_child instance through the c\_parent object's c\_children list property.

**Arguments**

* `path` (String)

**Returns**

this

**UpdateOperation.pathPush(path = null, body)**

Shortcut for updateOne(..., {$push: \[body]}).pathPrefix(path).execute()

**Arguments**

* `path` (String) Optional. Overrides `pathPrefix()`.
* `body` (Object) The value(s) to push.

**Returns**

Object

**UpdateOperation.pathUpdate(path = null, body)**

Shortcut for updateOne(..., {$set: \[body]}).pathPrefix(path).execute()

**Arguments**

* `path` (String) Optional. Overrides `pathPrefix()`.
* `body` (Object) The value(s) to update.

**Returns**

Object

**UpdateOperation.skipAcl(bool = true)**

Skips property acl checks.

**Arguments**

* `bool` (Boolean)

**Returns**

this

#### DeleteOperation

Operation defaults are dryRun(false), grant(null), skipAcl(false).

dryRun execute grant skipAcl

```
const Items = org.objects.c_items;

return Items.deleteOne({c_key: 'unique key'})
  .skipAcl()
  .grant(consts.accessLevels.delete)
  .execute();
```

**DeleteOperation.dryRun(bool = true)**

The operation performs a dry run. Though no documents are deleted, before triggers are called.

**Arguments**

* `bool` (Boolean)

**Returns**

this

**DeleteOperation.execute()**

Executes the operation.

**Returns**

Boolean true if the instance was deleted.

**DeleteOperation.grant(level)**

Sets the grant level for the operation.

**Arguments**

* `level` (Number)

**Returns**

this

**DeleteOperation.skipAcl(bool = true)**

Skips acl checks.

**Arguments**

* `bool` (Boolean)

**Returns**

this


---

# Agent Instructions: 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:

```
GET https://docs.medable.com/cortex-api/scripting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
