Ontology edits(本体编辑)¶
:::callout{theme="warning"} The following documentation is specific to TypeScript v1 functions. For more robust capabilities, including support for Ontology SDK and configurable resource requests, we recommend migrating to TypeScript v2. :::
In addition to writing functions that return derived values based on the Ontology, you can also write functions that edit the properties and links between objects in the Ontology. This page documents the object edit APIs available to you in functions. For more details about how edit functions work, refer to the overview page.
To actually be used in an operational context, Ontology edit functions must be configured as an Action, known as a function-backed Action. Configuring an Action in this way allows you to provide additional metadata, configure permissions, and access the Action in various operational interfaces. As noted in the documentation, running an edit function outside of an Action will not actually modify any object data.
:::callout{theme="warning" title="Warning"} Searching for objects after editing them may return unexpected results. See the Caveats section for details. :::
Declaring an edit function¶
Functions that edit the Ontology must:
- Be decorated with the
@OntologyEditFunction()decorator imported from@foundry/functions-api - Be decorated with the
@Edits([object type])decorator imported from@foundry/functions-apito specify the object types that will be edited - Have an explicit
voidreturn type
Updating properties¶
You can edit property values by simply reassigning the property value for an object. For example:
employee.lastName = newName;
If you access the lastName property value later in the same function execution, the new value that you just set will be returned.
Array properties on objects are generated with the ReadOnlyArray type. To modify an array, create a copy of it, modify the copy, then update the property:
// Copy to a new array
let arrayCopy = [...myObject.myArrayProperty];
// Now you can modify the copied array
arrayCopy.push(newItem);
// Then overwrite the property value
myObject.myArrayProperty = arrayCopy;
Note that you cannot update the primary key property value of an existing object.
Updating links¶
The SingleLink and MultiLink interfaces have various methods you can use to update links:
// Set an Employee's supervisor
employee.supervisor.set(newSupervisor);
// Clear an Employee's supervisor
employee.supervisor.clear();
// Add a new report to the given employee
employee.reports.add(newReport);
// Remove an old report associated with the given employee
employee.reports.remove(oldReport);
As with updating properties, accessing links after they have been updated reflects the updates you have made.
Creating objects¶
You can create new objects using the Objects.create() interface available from @foundry/ontology-api. When creating a new object, you have to specify a value for its primary key.
In this example, we create a new Ticket object with the given ID, set its dueDate property, and assign it to the given Employee (by modifying the assignedTickets link).
import { OntologyEditFunction, Edits } from "@foundry/functions-api";
import { Employee, Objects, Tickets } from "@foundry/ontology-api";
export class TicketActionFunctions {
@Edits(Employee, Tickets)
@OntologyEditFunction()
public createNewTicketAndAssignToEmployee(employee: Employee, ticketId: Integer): void {
const newTicket = Objects.create().ticket(ticketId);
newTicket.dueDate = LocalDate.now().plusDays(7);
employee.assignedTickets.add(newTicket);
}
}
Deleting objects¶
You can delete an object by calling the .delete() method.
In this example, we delete all the tickets assigned to the given employee.
const tickets = employee.tickets.all();
tickets.forEach(ticket => ticket.delete());
How edits are captured¶
When an Ontology edit function is executed, all updates to objects are captured by the functions infrastructure and returned at the end of the function execution. This includes new object creations via the Objects.create() API, all property updates, and object deletions.
Edits are collapsed intelligently so that the minimal set of edits are applied in an action. For example, if you create a new object and then update its properties, a single Create Object edit will be returned containing the property updates. Similarly, updating multiple properties of an existing object will return a single Update Object edit containing all of the property edits. Deleting an object will erase any other property edits that were done before the deletion. The entire function must succeed in order to generate the list of edits which is passed to the actions service executing the atomic transaction.
The captured Ontology edits are returned as a list from the function execution, which is why Ontology edit functions must have a return type of void or Promise<void>. When they are executed, the true return type of the function is a list of Ontology edits, so it is not possible to simultaneously return another value.
Edits are captured in a single edit store over the entire lifecycle of a single function execution. This means that it is possible to call into helper functions which create, update, or delete objects, even if those helper functions are not published as Ontology edit functions. For example:
export class HelperEditFunctions {
@Edits(ObjectA, ObjectB)
@OntologyEditFunction()
public createAndLink(): void {
const objectA = this.createObjectA();
const objectB = this.createObjectB();
objectA.linkToB.set(objectB);
}
/**
* Even though these helper functions are not annotated with @OntologyEditFunction(),
* they can create new objects for use in other edit functions.
*/
private createObjectA(): ObjectA {
const objectA = Objects.create().objectA(this.generateRandomId());
objectA.prop1 = "example";
objectA.prop2 = 42;
return objectA;
}
private createObjectB(): ObjectB {
const objectB = Objects.create().objectB(this.generateRandomId());
objectB.prop1 = "another example";
return objectB;
}
/* Generate your primary keys as needed. For example,
import { Uuid } from "@foundry/functions-utils";
private generateRandomId(){
return Uuid.random();
}
*/
}
Retrieving edited values¶
When edits are done in a function, the functions infrastructure will return the edited values when you read them. For example, setting a property of an object and then retrieving it will return the new value:
airplane.departureTime = newDepartureTime;
console.log(airplane.departureTime); // Will log newDepartureTime
Deleting an object will remove it from search results and prevent access to its properties.
The @Edits decorator¶
Actions may require provenance information to enforce its permissions. To provide actions with this information, you can use the @Edits decorator and specify the object types for which your function returns edits.
Consider the following when using the @Edits decorator:
- When editing properties, the type of the object that was edited should be declared.
- When editing one-to-one or one-to-many links, the type of the object with the foreign key property should be declared.
- When editing join table links, both the source and target object types should be declared.
:::callout{theme="warning"}
Functions perform static analysis of your code to automatically detect referenced object types. However, static analysis may fail to properly detect a reference. We strongly recommend that you always use the @Edits decorator to provide provenance information about referenced object types.
:::
For the following example, the object types Employee and Aircraft are edited by a function:
import { OntologyEditFunction } from "@foundry/functions-api";
import { Employee, Aircraft, Objects } from "@foundry/ontology-api";
export class MyOntologyEditFunction {
@Edits(Aircraft, Employee)
@OntologyEditFunction()
public myFunction(): void {
const x = Objects.search().aircraft().all()[0];
x.businessCapacity = 3;
const y = Objects.search().employee().all()[0];
y.department = "HR";
}
}
If you retrieve (or materialize) a previously edited object through the Objects.search() API, the edited value will be returned:
import { OntologyEditFunction } from "@foundry/functions-api";
import { Employee, Objects } from "@foundry/ontology-api";
export class CaveatEditFunctions {
@Edits(Employee)
@OntologyEditFunction()
public async editAndSearch(): Promise<void> {
const employeeOne = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
employeeOne.name = "Bob";
// Retrieve the already edited object
const employeeOneAgain = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
console.log(employeeOneAgain.name); // Prints "Bob"
}
}
中文翻译¶
本体编辑¶
:::callout{theme="warning"} 以下文档仅适用于 TypeScript v1 函数。如需更强大的功能(包括对 Ontology SDK 和可配置资源请求的支持),建议迁移至 TypeScript v2。更多信息请参阅语言特性支持。 :::
除了编写基于 Ontology 返回派生值的函数外,您还可以编写编辑 Ontology 中对象属性和链接的函数。本文档介绍了函数中可用的对象编辑 API。有关编辑函数工作原理的更多详情,请参阅概述页面。
要在实际操作环境中使用,Ontology 编辑函数必须配置为操作(Action),即所谓的函数支持的操作(function-backed Action)。通过这种方式配置操作,您可以提供额外的元数据、配置权限,并在各种操作界面中访问该操作。如文档所述,在操作外部运行编辑函数不会实际修改任何对象数据。
:::callout{theme="warning" title="警告"} 编辑对象后搜索对象可能会返回意外结果。详情请参阅注意事项部分。 :::
声明编辑函数¶
编辑 Ontology 的函数必须满足以下条件:
- 使用从
@foundry/functions-api导入的@OntologyEditFunction()装饰器进行装饰 - 使用从
@foundry/functions-api导入的@Edits([对象类型])装饰器来指定将被编辑的对象类型 - 具有显式的
void返回类型
更新属性¶
您可以通过直接重新赋值对象的属性值来编辑属性。例如:
employee.lastName = newName;
如果在同一函数执行过程中稍后访问 lastName 属性值,将返回您刚刚设置的新值。
对象上的数组属性以 ReadOnlyArray 类型生成。要修改数组,请先创建副本,修改副本,然后更新属性:
// 复制到新数组
let arrayCopy = [...myObject.myArrayProperty];
// 现在可以修改复制的数组
arrayCopy.push(newItem);
// 然后覆盖属性值
myObject.myArrayProperty = arrayCopy;
请注意,您无法更新现有对象的主键属性值。
更新链接¶
SingleLink 和 MultiLink 接口提供了多种更新链接的方法:
// 设置员工的上级
employee.supervisor.set(newSupervisor);
// 清除员工的上级
employee.supervisor.clear();
// 为指定员工添加新下属
employee.reports.add(newReport);
// 移除指定员工的旧下属
employee.reports.remove(oldReport);
与更新属性类似,更新后访问链接将反映您所做的更改。
创建对象¶
您可以使用 @foundry/ontology-api 提供的 Objects.create() 接口创建新对象。创建新对象时,必须为其指定主键值。
在以下示例中,我们使用给定的 ID 创建一个新的 Ticket 对象,设置其 dueDate 属性,并通过修改 assignedTickets 链接将其分配给指定的 Employee。
import { OntologyEditFunction, Edits } from "@foundry/functions-api";
import { Employee, Objects, Tickets } from "@foundry/ontology-api";
export class TicketActionFunctions {
@Edits(Employee, Tickets)
@OntologyEditFunction()
public createNewTicketAndAssignToEmployee(employee: Employee, ticketId: Integer): void {
const newTicket = Objects.create().ticket(ticketId);
newTicket.dueDate = LocalDate.now().plusDays(7);
employee.assignedTickets.add(newTicket);
}
}
删除对象¶
您可以通过调用 .delete() 方法删除对象。
在以下示例中,我们删除分配给指定员工的所有工单。
const tickets = employee.tickets.all();
tickets.forEach(ticket => ticket.delete());
编辑的捕获方式¶
当执行 Ontology 编辑函数时,所有对对象的更新都会被函数基础设施捕获,并在函数执行结束时返回。这包括通过 Objects.create() API 创建的新对象、所有属性更新以及对象删除。
编辑会被智能合并,以便在操作中应用最少的编辑集。例如,如果您创建了一个新对象并随后更新其属性,将返回一个包含属性更新的创建对象编辑。同样,更新现有对象的多个属性将返回一个包含所有属性编辑的更新对象编辑。删除对象将清除删除之前所做的任何其他属性编辑。整个函数必须成功执行,才能生成传递给执行原子事务的操作服务的编辑列表。
捕获的 Ontology 编辑会以列表形式从函数执行中返回,这就是为什么 Ontology 编辑函数的返回类型必须是 void 或 Promise<void>。当它们被执行时,函数的实际返回类型是一个 Ontology 编辑列表,因此无法同时返回其他值。
编辑在单个函数执行的整个生命周期内被捕获到单个编辑存储中。这意味着可以调用辅助函数来创建、更新或删除对象,即使这些辅助函数并未发布为 Ontology 编辑函数。例如:
export class HelperEditFunctions {
@Edits(ObjectA, ObjectB)
@OntologyEditFunction()
public createAndLink(): void {
const objectA = this.createObjectA();
const objectB = this.createObjectB();
objectA.linkToB.set(objectB);
}
/**
* 即使这些辅助函数没有使用 @OntologyEditFunction() 注解,
* 它们也可以创建新对象供其他编辑函数使用。
*/
private createObjectA(): ObjectA {
const objectA = Objects.create().objectA(this.generateRandomId());
objectA.prop1 = "example";
objectA.prop2 = 42;
return objectA;
}
private createObjectB(): ObjectB {
const objectB = Objects.create().objectB(this.generateRandomId());
objectB.prop1 = "another example";
return objectB;
}
/* 根据需要生成主键。例如,
import { Uuid } from "@foundry/functions-utils";
private generateRandomId(){
return Uuid.random();
}
*/
}
检索编辑后的值¶
当在函数中执行编辑时,函数基础设施会在读取编辑后的值时返回这些值。例如,设置对象的属性然后检索它将返回新值:
airplane.departureTime = newDepartureTime;
console.log(airplane.departureTime); // 将输出 newDepartureTime
删除对象会将其从搜索结果中移除,并阻止访问其属性。
@Edits 装饰器¶
操作可能需要来源信息(provenance information)来强制执行其权限。为了向操作提供这些信息,您可以使用 @Edits 装饰器并指定函数返回编辑的对象类型。
使用 @Edits 装饰器时请注意以下几点:
- 编辑属性时,应声明被编辑对象的类型。
- 编辑一对一或一对多链接时,应声明具有外键属性的对象类型。
- 编辑连接表链接时,应同时声明源对象类型和目标对象类型。
:::callout{theme="warning"}
函数会对代码进行静态分析以自动检测引用的对象类型。然而,静态分析可能无法正确检测到引用。我们强烈建议您始终使用 @Edits 装饰器来提供关于引用对象类型的来源信息。
:::
在以下示例中,函数编辑了对象类型 Employee 和 Aircraft:
import { OntologyEditFunction } from "@foundry/functions-api";
import { Employee, Aircraft, Objects } from "@foundry/ontology-api";
export class MyOntologyEditFunction {
@Edits(Aircraft, Employee)
@OntologyEditFunction()
public myFunction(): void {
const x = Objects.search().aircraft().all()[0];
x.businessCapacity = 3;
const y = Objects.search().employee().all()[0];
y.department = "HR";
}
}
如果您通过 Objects.search() API 检索(或物化)之前编辑过的对象,将返回编辑后的值:
import { OntologyEditFunction } from "@foundry/functions-api";
import { Employee, Objects } from "@foundry/ontology-api";
export class CaveatEditFunctions {
@Edits(Employee)
@OntologyEditFunction()
public async editAndSearch(): Promise<void> {
const employeeOne = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
employeeOne.name = "Bob";
// 检索已编辑的对象
const employeeOneAgain = Objects.search().employee().filter(e => e.id.exactMatch(1)).all()[0];
console.log(employeeOneAgain.name); // 输出 "Bob"
}
}