-
-
- Search Engine Optimization
- OTP
- User Interface migration guide
- User account management
- Instructies voor implementatie van visueel editen van nieuwsbrieven
- Login as another user
- Support
- More information about moving to User Interface Version 4.0
- Standaard page layout
- Sections moved to layout
- Aanpassingen in release 2024-7
- Media library
- Aanpassingen in release 2024-10
- Analytics and Matomo
- Registration forms
- How to change names of classes and fields?
- Responsible Disclosure Policy
- How to upload a blob in Velocity?
- Aanpassingen in release 2024-2
- Instances
- Google Analytics
- Street and City helper (postcodecheck)
- Responsible disclosure-beleid
- Postcode check service (straat en huisnummer) kosten
- Expressions
- Regular Expression Reference
Field routes
This page describes the concept of routes and field routes in scripts.
Using class relations to get values from other records
In the blueprint of your application, you will most likely have defined a number of classes, and some of those classes are related to other classes, by means of a foreign key field. To retrieve data (values) from a class that is related to the class of a record in a script, you could implement some code to get a hold of those related records and get the desired values from those. For example, consider the classes "order" and "order line", where order line has a foreign key field "Order" pointing to class "order" (which is to say that "order" is the foreign class of "order line", and "order line" is the connected class of "order".) If you have a record of class "order line" (in variableorderLine), and you'd like to get the value for the field "Total amount" from the related "order" record, you can use the method Record.getForeignRecord and specify the foreign key field defining the class relation:
let order = orderLine.getForeignRecord(Classes.order_line.Order);
return order.get(Classes.order.Total_amount);
In this example, the class relation between classes "order" and "order line" as defined by the foreign key field "order line.Order" is used to retrieve the foreign "order" record of a given "order line" record. This is all very straightforward, but things get slightly more complicated if we use this class relation in the other direction. Let's say you have a record of class "order" (variable order), and you want to get a list containing the values for the field "order line.Quantity" for each order line related to that order. A typical implementation, using the Record.getConnectedRecords method would look like this:
let values = [];
for (let orderLine of order.getConnectedRecords(Classes.order_line.Order)) {
values.push(orderLine.get(Classes.order_line.Quantity));
}
return values;
By itself, the above implementation is not terribly complex, but in more elaborate scripts that require many operations involving class relations, repeatedly having to write this out in code may become a bit cumbersome, especially when you are dealing with multiple levels of class relations ("a connected class of a connected class of a foreign class").
Route theory
Routes provide an abstraction for getting values from records that are directly or indirectly related to a certain record, that eliminates the need to write code just to get these records. Simply put, a route consists of a sequence of (one or more) class relations, each accompanied by an instruction on which direction to follow that relation. Each such element in a route is called a segment. A route describing how to get from an "order" to its "order lines" would have a single segment consisting of the class relation defined by foreign key field "order line.Order" and the direction "foreign to connected class". The same segment with the direction "connected to foreign class" described how to get from an "order line" to the related "order".
This simple route can be extended to include another segment. Let's say every "order line" has a relation to a "product", via foreign key field "order line.Product". We can simply add a segment for this relation, with direction "connected to foreign class", to end up with a route, now consisting of two segments, that describes how to get from an "order" to all "products" of its "order lines".
Now we have defined a route from a class to some (more or less remotely) related class, we want to use this route to retrieve values from "remote" records. Before we are able to do this, we have to take one last step: specify in which field in the remote class (the "end class" of the route) we are interested, by creating a field route, which in its simplest form is the combination of a field and a route. Once this last step is done, we can simply supply the resulting field route as the argument to the get() method of any record of the "start class" of the route, as we will do in the following section of his document.
Using a field route in a script
To create a route from a certain class in your blueprint to another (related) class, the Class type has the method to(class, field...). The first argument is the other class to create a route to, the next arguments specify the foreign key field(s) that define the precise class relation to use. (Note that it is permitted to not specify any foreign key field, and this is fine when there is only one relation between the classes, but this method will break as soon as more class relations exist - which may also be the result of a future change in your data model. It is therefore advisable to always specify the foreign key fields defining the relation.) For example, to create the abovementioned route from class "order" to class "order line", using "order line.Order":
let route = Classes.order.to(Classes.order_line, Classes.order_line.Order);
The resulting object (of type Route) can now be further extended to lead to class "product", by invoking a similar to(class, field...) method in type Route:
route = route.to(Classes.product, Classes.order_line.Product);
The Route object in route now consists of two segments, leading from class "order" to class "product". If, for instance, we want to have a look at the values of field "Product code" in the products specified by the order lines of our order, we have to combine that field with our route to create a field route. This is done by invoking the method from(route) on this field:
let fieldRoute = Classes.product.Product_code.from(route);
Now we are ready to use our field route on any record of class "order". The following full example demonstrates this for an "order" record (note that the to() and from() method calls are chained for better readability):
let fieldRoute = Classes.product.Product_code.from(
Classes.order
.to(Classes.order_line, Classes.order_line.Order)
.to(Classes.product, Classes.order_line.Product)
);
return order.get(fieldRoute);
The script will, using the specified field route, automatically return a list of all product codes of the products in the order lines belonging to the order. Note that get() with a field route argument will return a list of values as soon as one class relation is used in the foreign-to-connected-class direction (1:n). If all segments are from a connected to a foreign class, a single value may be returned.
Other uses of field routes
In the above it is demonstrated how to use field routes to retrieve values from records that are related to a record you have in your script. There are however other uses, for example, type Query has a method addFilter() that accepts a FieldRoute object (it actually accepts a DataField, which is an specification both the Field and FieldRoute types comply with). This allows you to execute a query on a class using a filter on a related class:
let fieldRoute = Classes.product.Product_code.from(
Classes.order
.to(Classes.order_line, Classes.order_line.Order)
.to(Classes.product, Classes.order_line.Product)
);
let query = new Query(Classes.order);
query.addFilter(fieldRoute, "NON_FOOD");
return query.find();
This script will return all order records that have one or more order lines for a product with product code "NON_FOOD".
Similarly, the filter(), get(), getGroups(), and order() methods of type RecordList accept FieldRoute arguments.