Fields 

What is a field? 

A field refers to one specific attribute of each record stored for a model. Like columns in traditional databases, a field records a characteristic or property about the model's subject matter. Fields define the overall structure of the model's storage, deciding the names, datatypes, and validations on all the data a model stores.

For example, take a model representing each customer of an ecommerce system. The customer model captures the information related to each person who bought something, such as their name and date of birth. In Gadget, each attribute becomes a field, which then stores a value for each record. For our example customer model, we might create these fields:

  • name (field type: string ) - stores the customer's full name.
  • dateOfBirth (field type: date / time ) - stores the customer's birth date.

You can think of each field as a column in a spreadsheet, and each record as a row.

Field defaults 

In Gadget, you can set a default value for most field types in the schema editor. This default value will be used when creating a record if no specific value is provided. You can modify the default value anytime, but the change will only affect new records created afterward.

Types of fields 

Field typeDescription
stringStores an arbitrary length string with UTF-8 encoding.
numberStores a numerical value, optionally with a certain precision. Used to store both integers, floats, and arbitrary precision values.
idStores a unique identifier for each record in this model. IDs are unique within the model, but not across models.
enumStores one string or a list of strings picked from a global list of allowed values. Can also be configured to accept any string as a valid input. Similar to an enum in traditional SQL databases.
rich textStores an enhanced-Markdown formatted string. Can produce formatted HTML for the markdown.
booleanStores a true or false value.
date / timeStores a date or date and time value with a timezone. Accepts and serves data as an ISO-8601 string. Fields configured to not include time will ignore the time / timezone portion of input strings.
emailStores an email as a string.
urlStores a URL as a string.
fileStores a file, like an image or a PDF, in cloud storage. See storing files for more information.
colorStores a hexadecimal representation of a color.
vectorStores a vector of floats. Useful for storing embeddings and performing vector operations like cosine similarity.
jsonStores any JSON value. Any valid JSON is accepted.
passwordStores a bcrypt hashed password. One way encrypts the value, so the unencrypted text can't later be retrieved. Suitable for storing passwords and other secrets you might need to compare against but not reveal.
encrypted stringStores a string that is encrypted at rest and decrypted when accessed for extra security. Suitable for storing secrets whose contents you need later.
role listStores a list of roles.
computedDynamically generates values based on Gelly snippets involving other fields. See computed fields for more information.

Working with a record state field 

The shopifyShop model includes a record state field that stores a specific status for each record. While using record state for implementing business logic is optional, it can be a useful way to determine permissions and actions.

Rather than relying on generic operations like create, update, and delete, Gadget allows you to define specific and meaningful actions such as publish, fulfill, or complete. Each action can transition a record from one state to another. For example, publishing a record may move it from the Unpublished state to the Published state, while completing a task can move it from Not Started or Doing to Done.

The record state field holds the current state of each record. The field configuration panel defines the available states for this field.

Default system fields 

Each model in Gadget has three fields managed by default. These fields are:

  • id: This field captures a unique ID for each of your records within a table

Gadget will automatically handle ID assignments. To ensure performance and stability, Gadget auto-increments IDs on every new mutation regardless of the status of the mutation. As a result, your saved records will always have a unique ID, but the IDs are not guaranteed to be sequential. As an example, your IDs may increment from 11 to 13, as the mutation to create the 12th record failed.

  • createdAt: This field captures the timestamp at record creation
  • updatedAt: This field captures the timestamp of the last event which changed the record

System fields cannot be given a different name / API identifier.

Computed fields 

Produces a value according to a Gelly code snippet using other field values.

For more information, see our computed fields guide

Extending fields with validations 

In Gadget, validation is an extension of the field component of a model that helps prevent the entry of malformed or inconsistent data into your system. When modifying records, Gadget verifies that any new data satisfies the validations defined for each field. If an action attempts to write invalid data, it will be unsuccessful, and the invalid data will not be saved.

When making API calls to write data, Gadget provides structured error messages that indicate what data is invalid. These error messages can be presented directly to users, helping guide them in correcting the problematic data.

Validations play a crucial role in maintaining data integrity and ensuring that only valid and coherent data is stored in your system. They serve as a safeguard against incorrect or incompatible data and facilitate a smooth user experience by providing clear feedback on data entry errors.

Applicable validations to field types 

Gadget offers a selection of common validations for each field type. These vary from one field type to another:

Field typeApplicable Validations
stringRequired, Uniqueness, String Length Range, Run Code Snippet, RegExp Pattern
numberRequired, Uniqueness, Number Min/Max Range, Run Code Snippet
idNo applicable validations
enumRequired, Uniqueness, Run Code Snippet
rich textRequired, Uniqueness, String Length Range, Run Code Snippet, RegExp Pattern
booleanRequired, Uniqueness, Run Code Snippet
date / timeRequired, Uniqueness, Run Code Snippet, RegExp Pattern,
emailRequired, Uniqueness, String Length Range, Run Code Snippet, RegExp Pattern
urlRequired, Uniqueness, String Length Range, Run Code Snippet, RegExp Pattern
fileRequired, File Size Range, Image File, Run Code Snippet
colorRequired, Run Code Snippet, Color
jsonRequired, Uniqueness, Run Code Snippet
vectorRequired, Uniqueness, Vector Dimensions, Run Code Snippet
passwordNo applicable validations
encrypted stringNo applicable validations
role listNo applicable validations
computedNo applicable validations

Required validation 

A required validation refers to the process of ensuring that a particular input or data field is not empty or null when it is required to have a value. It is a form of data validation that checks whether a user has provided the necessary information before proceeding with a certain operation or action.

Uniqueness validation 

The Uniqueness validation in Gadget ensures that each value for a field occurs only once in the database. It is commonly used for fields like email or username to guarantee that each value is unique within the system.

Underlying database constraints are leveraged to enforce the uniqueness validation reliably, even in transactional contexts and under load.

If a Uniqueness validation is added to a model that already contains data, the setup may fail if there are duplicate values for the field. In such cases, the uniqueness constraint is not enforced until the duplicate data is corrected by either deleting records or modifying the field values to ensure uniqueness. Once the data is made unique, the validation can be re-added and verified to succeed.

The Uniqueness validation can be configured as case-sensitive or case-insensitive by toggling the Case Sensitive option. When the option is disabled, values are considered duplicates regardless of letter casing. This is useful for scenarios like URL slugs or emails, where users may enter values with different casing but uniqueness should be maintained regardless of casing.

Number Min/Max range validation 

Number min/max range validation ensures whether a numeric value falls within a specified range of minimum and maximum values. It is commonly used to ensure that numeric input or data meets certain constraints or requirements.

String length range validation 

String length range validation is a type of data validation that ensures whether a string has a specific length or falls within a certain range of lengths. It is commonly used to enforce length restrictions or requirements on user input or data fields

Image validation 

The Image File validation ensures that uploaded files meet three criteria:

  1. They have an image based MIME type or subtype — see MDN's reference.
  2. They are in one of the following image file formats: gif, jpg, png, svg, or webp (common web formats); apng, bmp, bpg, cr2, cur, dcm, flif, heic, ico, jp2, jpm, jpx, jxr, psd, or tif (additional formats).
  3. They do not contain an animation if the Allow animated images option is disabled.

File size range validation 

File size range validation ensures the size of a file falls within a specified range of acceptable sizes. It is commonly used when handling file uploads or processing files in applications. By validating the file size, you can control resource consumption, prevent server overload, and maintain data integrity.

Color Validation 

Color validation ensures whether a given value represents a valid color. It is typically used to ensure that color values provided by users or within a system adhere to a specific format or range of valid colors.

Vector dimension validation 

The Vector dimensions validation in Gadget ensures that all vectors stored in a field have the same count of dimensions.

It's important to note that Gadget restricts the sorting or filtering of vectors unless all the stored vectors and input vectors have the same dimension count. This is because many vector operations used in Gadget are not defined for vectors with different dimensions.

To enforce the consistency of vector dimensions, you can add a Vector dimensions validation to a field. This validation ensures that all vectors stored in the field have the same number of dimensions.

For more details about this validation and any related errors, you can refer to the GGT_DIFFERENT_VECTOR_DIMENSIONS error in the Gadget documentation.

RegEx pattern validation 

RegExp also known as regular expression pattern validation, is used to validate strings or data against a specific pattern or format using regular expressions. Regular expressions (RegEx) are sequences of characters that define a search pattern, allowing for powerful and flexible pattern matching and validation.

Gadget uses the RegExp engine built into node.js to run RegExp Pattern validations. For information on how to write JavaScript regular expressions, please refer to MDN's reference.

Adding custom code validation 

In Gadget, you can add your custom validations written in JavaScript. The custom validation runs a JS function each time a record is created or updated to check if that change should succeed. If the function reports no errors, then the save will be complete, and if the data is somehow invalid, the validation can add structured error messages to the different fields of the record being changed.

Each custom validation file must export a function as the default export function from the module. The function can be marked async or return a Promise. The function shouldn't return anything and, instead, should add errors to any fields determined to be invalid using the passed-in errors object, which holds a structured set of errors keyed by a field.

Validation functions get passed one big context object and not individual arguments. This is because there are a lot of arguments you may or may not need. Most Gadget users use JavaScript destructuring to pull out just the context keys that they need. The most common keys used from the context are the record itself at the record key, the api object, which is an already set up instance of the JavaScript client for the application at api, and the Errors object at the errors key.

Here's a custom validation that tests if a record's full name is not null and its last name is also not null:

JavaScript
1import type { FooBarFieldValidationContext } from "gadget-server";
2
3export default async ({
4 api,
5 record,
6 errors,
7 logger,
8 field,
9}: FooBarFieldValidationContext) => {
10 if (record.firstName && !record.lastName) {
11 errors.add("lastName", "must be set if the first name is set");
12 }
13};
1import type { FooBarFieldValidationContext } from "gadget-server";
2
3export default async ({
4 api,
5 record,
6 errors,
7 logger,
8 field,
9}: FooBarFieldValidationContext) => {
10 if (record.firstName && !record.lastName) {
11 errors.add("lastName", "must be set if the first name is set");
12 }
13};

Here's a validation that tests if a record's phone number is valid:

JavaScript
1import PhoneNumber from "awesome-phonenumber";
2import type { FooBarFieldValidationContext } from "gadget-server";
3
4export default async ({
5 api,
6 record,
7 errors,
8 logger,
9 field,
10}: FooBarFieldValidationContext) => {
11 const number = new PhoneNumber(record["customerPhoneNumber"]);
12 if (!number.isValid()) {
13 errors.add("customerPhoneNumber", "is not a valid phone number");
14 }
15};
1import PhoneNumber from "awesome-phonenumber";
2import type { FooBarFieldValidationContext } from "gadget-server";
3
4export default async ({
5 api,
6 record,
7 errors,
8 logger,
9 field,
10}: FooBarFieldValidationContext) => {
11 const number = new PhoneNumber(record["customerPhoneNumber"]);
12 if (!number.isValid()) {
13 errors.add("customerPhoneNumber", "is not a valid phone number");
14 }
15};

If a validation function throws an error while executing, the action validating the current record will fail, and if the action is transactional, any operations performed in the run function will be rolled back.

Was this page helpful?