Entities

Explanation of what entities are, features they have, and how they are used.

Entities are the fundamental concept in a Slingr app. They define both the data structure and the behavior of an app. Entities can represent various entities like companies, people, tasks, projects, and more.

Once an entity is created, you can create records within that entity. For instance, if you have an entity named companies, each individual company under that entity will be treated as a record.

An entity defines the following aspects:

  • Settings: These encompass details such as name, label, audit logs, indexes, etc.
  • Fields: Fields establish the structure of the entity, affecting both the database and the UI.
  • Actions: Here, you can define the “behavior” or actions associated with the entity.
  • Permissions: Specify who has access to operations, actions, and fields within the entity.

Settings

Label

The label represents a human-readable name for the entity. It can include spaces, special characters, and a mixture of uppercase and lowercase letters.

This label is used as a reference for the entity within the user interface. Changing the label of an entity does not require any data restructuring.

Name

The name is the internal identifier for the entity. It cannot contain special characters or spaces.

This name serves various purposes within the app:

  • Database: Records for the entity are stored under this name.
  • REST API: The automatically generated REST API uses this name for URLs.
  • Scripts: Scripts often reference the entity by its name.

Changing the entity’s name impacts all of the above aspects.

Database changes are handled automatically by the platform when changes are pushed, eliminating the need for manual intervention.

Changes in the REST API are also managed automatically. However, if external apps are using the REST API, those apps might require adjustments.

Scripts using the entity name need manual updates. We plan to provide assistance for these cases in the near future.

Type

The type setting defines the behavior of the entity:

  • Data: This signifies that the entity holds app data. It’s the default and most common option. Data in this entity is excluded from backups and doesn’t synchronize between environments and linked apps.
  • Enum: These entities usually contain a small number of records that contribute to the app’s metadata, such as order types or states. Records in this entity are included in backups and synchronized across environments and linked apps. Sync behavior options include:
    • Not syncing: The entity acts like a data entity, with no record synchronization.
    • Create new records: Only new records are synced; existing records in the target environment aren’t deleted or updated.
    • Create and update records: New and existing records are synced; changes to existing records in the target environment are overwritten.
    • Full sync: Synchronization ensures records in the target environment match those in the source environment, potentially leading to record deletions.
  • Calculated: This type calculates entity data. It’s useful for representing external data in the app, and behaves the same as Data entities.
  • System: Platform-created and managed entities that can be extended with custom configurations like fields and actions. Autogenerated metadata for these entities is immutable. They reside under the System folder. An example is the Users entity, created during app provisioning.

Parent entity

Entities can inherit from other entities, reducing redundancy in the app.

Inheriting from a parent entity provides access to the parent entity’s fields, actions, and indexes within the child entity.

Abstract

Setting an entity as abstract when inheriting means instances of this entity won’t exist. Views can’t be created for abstract entities.

Record label

Records possess a label used as a summary in various app contexts. For instance, in relationship fields, the label appears when selecting a record.

Typically, the label should represent the record’s content. For example, if the entity contains individual information, the label could be the person’s full name.

Two methods exist to define record labels:

  • Field: Select an entity field whose string value serves as the record’s label.
  • Script: For more flexibility, write a script returning the record’s label.

Parameters
NameTypeDescription
recordsys.data.RecordThe record where the label is being calculated.
Returns

string - You should return the label of the record.

Samples
// builds the label using first and last names
return record.field('firstName').val()+' '+record.field('lastName').val();


Modifying the record label definition triggers data refactorings across the entity’s records. This also applies to records within entities that possess relationship fields pointing to records in the entity where the label was altered.

Indexes

Indexes play a crucial role in enhancing query performance and follow the principles of traditional databases. For instance, if your entity comprises a substantial number of records and you frequently query by the sku field, creating an index for the sku field can significantly expedite those queries and mitigate the need for full scans.

Indexes can be generated directly within the Indexes section of an entity. Alternatively, they are automatically generated when you designate a field as Unique or Indexable.

Each index encompasses the following properties:

  • Name: This signifies the index name in the database. It is automatically computed and unalterable.
  • Type: The index type is automatically determined based on the chosen fields. Possible types encompass:
    • Normal: Regular indexes.
    • Relationship: Created for fields applied to relationships, users, groups, or files. Comprises ID and label indexes.
    • Compound: Generated when multiple fields are selected.
  • Status: Denotes the present index creation status. While you can create the index in the builder, it won’t manifest in the database until changes are pushed or synced. During index creation, potential issues might arise, and the status helps ensure successful creation.
  • Unique: This flag indicates whether index values must be unique. If duplicate values exist in existing records, index creation will fail.
  • Fields: Lists the fields forming the index. Remember that in queries, all indexed fields must be queried to utilize the index effectively.

Adding or removing indexes results in the construction or removal of indexes, which can be time-consuming for entities with numerous records. It’s important to note that indexes entail overhead during record creation, update, and deletion, as they need to be updated. Hence, make sure to only generate indexes when they are genuinely essential.

Enabling the Allow Global Search flag initiates index creation, thereby enabling efficient word-based querying across all fields of the record. This feature significantly enhances the ability to search across the contents of various fields.

For more details on how Global Search operates, refer to this documentation.

Record validations

Record validations empower you to execute intricate validations encompassing all fields within a record. Moreover, they facilitate interaction with external services, capabilities that are beyond the scope of field-level rules.

For instance, you might possess an endpoint for address validation services that can be utilized to validate addresses. Alternatively, you might require certain fields to conform to specific patterns when specific options are selected.

This is the script context:


Parameters
NameTypeDescription
recordsys.data.RecordThe record to validate.
Returns

object[] - You should return an array of errors.

To handle errors effectively, return an array of error objects following this structure:

  • path: This corresponds to the field’s location with issues. For nested fields like address.zipCode, provide the full path. For multi-valued fields, specify the index, such as addresses[1].zipCode.

  • code: Assign an appropriate error code. This code will be included in the response when attempting to create/update a record via the REST API or as exception information when saving a record with the JavaScript API.

  • message: Craft a descriptive error message that will not only be displayed in the user interface but also sent in response, along with the associated error code.

[
  {
    path: 'addressLine',
    code: 'invalid',
    message: 'This is not a valid US address'
  },{
    path: 'zipCode',
    code: 'invalid',
    message: 'This is not a valid US zip code'
  }
]

Samples
// validates the zip code using an external service
var errors = [];
var zipCode = record.field('address.zipCode').val();
if (!app.endpoints.addressValidator.isValidZipCode(zipCode)) {
  errors.push({
    path: 'address.zipCode',
    code: 'invalid',
    message: 'This is not a valid US zip code'
  });
}
return errors;


Lookup fields

Fields configured with this feature are considered during record retrieval. To look up a specific record, these fields are used in conjunction with the default system fields: ID and label.

Lookup fields require the unique flag to be enabled.

Detailed logs

This feature enables more detailed logging for various record operations: create, edit, delete, and the execution of actions on data records.

Activate this feature at the entity level through this setting:

  • Enable Detailed Logging: Toggle to enable detailed logging for record operations.

Audit logs

This feature allows you to log changes in records, which is useful for auditing purposes. You can track when a record was created, the different changes made to it over time, as well as the modified fields and people involved in those changes.

When audit logs are enabled for an entity, you can query logs for a specific record (or even all records at the same time) using the REST API or the UI. See AuditLogs for more details.

Several settings control what gets logged in the audit trail of records:

  • Logs Expiration: Define rules to determine when logs should expire.
    • Delete Policy: Indicate what to do with the audit logs of a record when it is deleted.
      • Expire When Record Is Deleted: Delete the audit logs when the record is deleted.
      • Keep Audit Logs: Keep the audit logs of the record. When this option is selected, specify how long the audit logs will be kept (e.g., number of days, weeks, or months).
  • User Events: Track changes made as a consequence of an external request, such as from the REST API or the UI. These events include:
    • Ignore Fields: Exclude specific fields from change tracking when changes are made through the REST API or the UI. This can be useful for fields that are updated frequently or contain extensive content.
    • Record Created: Log the creation of records via the REST API or the UI.
    • Record Changed: Log updates to records via the REST API or the UI.
    • Record Deleted: Log record deletions via the REST API or the UI.
    • Action Executed: Log the execution of actions on individual records via the REST API or the UI.
  • Events from Scripts: These are events generated from scripts in the app, such as when a script uses the method ‘sys.data.save()’.
    • Ignore Fields: Exclude specific fields from change tracking when changes are made from a script in the app. This can be useful for fields that are updated frequently or contain extensive content.
    • Record Created: Log the creation of records from a script in the app.
    • Record Changed: Log updates to records from a script in the app.
    • Record Deleted: Log record deletions from a script in the app.
    • Action Executed: Log the execution of actions on individual records from a script in the app.
  • System Events: These events result as side effects of other operations. For example, updating the label of a record that is referenced by another record will update the relationship. Generally, you don’t want to track these kinds of changes.
    • Cascade Updates: These events are generated when a change in one record needs to be propagated to other records. For instance, when copied fields in a relationship field are updated in a record, they need to be copied to relationship fields referencing that record.
    • Refactorings: If this flag is set, when changes are made in the entity definition that lead to refactorings on records (e.g., field deletion or label changes), a log for it will be created.

Data generation settings

These settings are only available for Calculated Entities.

Schedule time expression

This expression determines when the script for generating data should run. The minimum supported frequency is 15 minutes. Refer to this documentation for more information on the format of the expression.

Condition type

Choose whether data should always be generated when the time expression is met or if you want to evaluate it using a script.

Condition

This script determines if data should be regenerated and is only available if you choose Script as the condition type. The script should return true if regeneration is necessary or false otherwise. The Data Generation Script will only run if this script returns true.

Data generation script

This script should return a list of either Record objects or JSON objects that can be mapped to a Record object.

Behavior during regeneration

This flag allows to configure the behavior when data it’s being generated. It applies to data queries.

  • If the flag it’s set to true, when trying to read any data for this entity, if data it’s being generated at that moment, that read operation will wait until data generation ends.
  • If the flag it’s set to false, when trying to read any data for this entity, if data it’s being generated at that moment, an AccessForbiddenException will be thrown.

Fields

Fields define what information will be stored in records of the entity.

Slingr allows to have more complex structures than you usually can use in traditional relational database. For example it is allowed to have multi-valued fields as well as nested fields. These features make it is easy to define a more natural model.

For example you might have an entity with this structure:

  • name
  • type
  • phoneNumbers (multi-valued)
  • addresses (multi-valued)
    • addressLine
    • zipCode
    • state

Each field has a type, which defines which data can be stored there as well as rules and display options. You can check the copied field types here.

Apart from the type-specific settings, all fields share some common features. For more details check Fields.

There are two special field types that are worth mentioning:

Changes on fields and data refactorings

If you make changes to the structure of the entity by removing fields or making changes to existing fields in a way that affect the data structure (for example you change the field name), when those changes are pushed or synced, data refactorings will be done to adjust all records to the new structure.

For example if you rename a field from type to category, when changes are pushed or synced a refactoring over all records will be done to rename field type to category.

A more complex case happens when you change the type of the field. Let’s suppose that the field itemCode was an integer field but it is changed to a text field. In this case the data refactoring will convert numbers to strings and the value will be preserved.

However, if you are converting in the other way around, the conversion might not be valid in some cases. For example if the value was the string "10", then it can be safely converted to the number 10, but if the value was A10 then it is not a valid integer number and the field value will be set to null.

The rule during conversions is that the original value will be converted to its string representation, and the new type will try to parse that string representation. If the parsing fails, the value will be set to null.

Finally, another conversion that can affect the structure is multiplicity changes. If a field is changed from single-valued to multi-valued, existing value will be set as the first value in the field. On the other hand, if the multiplicity is changed from multi-valued to single-valued, only the first value will be kept, discarding any additional value of the field.

Changes in rules

If there are changes in the rules of a field, it is possible that records that were valid before are not longer valid. For example you have a text field and you add a maximum length of 10 characters. If there were already records with values longer than 10 characters for that field, those records won’t be valid any longer.

When this happens records will be kept as they are. If you try to update them the validation error will show up and you will need to fix it before proceeding.

Actions

Actions allow to define some behavior on records. For example, in an entity that holds tasks, you could have an action to complete it, that will check that all pre-conditions are met, update the status and notify people involved in the task.

There are basically two types of actions:

  • One record: these actions are applied to one record at a time. Even when it is possible to select many records through the UI or send many IDs on the REST API, this action will be applied at one record at a time. The action doesn’t know how many records are involved, it is only aware of the record the action is being applied.
  • Many records: these actions take a query as parameter that defines the selection of records. This way the action knows all the records involved and it can do something with all of them at the same time. For example you could have an action to send a summary of many tasks in one email, which is not possible to do with actions that are executed over individual records.

For more information about actions, please check the documentation for Actions.

Record listeners

Record Listeners can be hooked to different record events, like record created, changed, action executed, etc.

Those listeners will be listed in the entity, however they can also be managed from the Model > Listeners section in the app builder.

For Caculated entities they have a different behavior. These listeners are used to update the records and they will be only listed in the calculated entity.

For more information check the documentation of Listeners.

External listeners

These listeners are only available for Caculated entities. External Listeners can be hooked to different record events, like record created, changed, action executed, etc.

Those listeners will be listed in the entity, however they can also be managed fromthe Model > Listeners section in the app builder.

For more information check the documentation of Listeners.

Permissions

Permissions allow to define which operations can be done for each group on records of the entity.

Permissions for an entity can be handled right in the entity definition, but it is just a different view of what you can configure in groups. It is oriented so you can easily configure permissions on the entity for all existing groups.

When a new entity is added, no permissions are added to any group by default.

For more information about permissions please refer to Groups.