从 TypeScript v1 迁移到 v2
这是一份逐项语法对照的迁移手册:函数声明、包引用、日期时间、SDK 生成、查询写法、过滤/分组/聚合的映射,以及对象标识和编辑。
https://www.palantir.com/docs/foundry/functions/typescript-v2-migration/
原始标题:TypeScript v2 > Migrate from TypeScript v1 to TypeScript v2
先记住这几条
写在前面
本指南描述将现有 TypeScript v1 函数迁移到 v2 时,你可能遇到的语法与结构差异。请参阅特性支持文档,了解 v2 的增强以及每个版本支持的内容。
函数声明方式
函数声明方式
要在 TypeScript v1 中将函数发布到平台,你必须用 @foundry/functions-api 包中的 @Function() 装饰器标注它,并且该函数必须是仓库根 index.ts 文件导出的类的一个方法。
// src/index.ts
import { Function } from "@foundry/functions-api";
export class MyFunctions {
@Function()
public reverseStringArray(arr: string[]): string[] {
return arr.reverse();
}
}要在 TypeScript v2 中将函数发布到平台,你必须将它写在 src/functions 目录下的一个文件中,并用 export default 导出。每个文件只能导出一个函数。
// src/functions/reverseStringArray.ts
export default function reverseStringArray(
arr: string[]
): string[] {
return arr.reverse();
}为了让仓库保持有序,我们建议将相关函数分组到 src/functions 目录下的子目录中。例如,下面的文件夹结构将函数组织进 payroll 与 staffing 子目录,使职责划分更清晰。

有关更多信息,请参阅我们关于TypeScript v2 函数上手的文档。
改用 @osdk/functions 包
改用 @osdk/functions 包
在 TypeScript v1 中,你必须从 @foundry/functions-api 包导入像 Integer 与 Double 这样的基本类型,才能在签名中使用它们。而在 TypeScript v2 中,你必须改用 @osdk/functions 包。
下面的例子从 @foundry/functions-api 包导入 Integer 类型,并在一个 TypeScript v1 函数的签名中使用它,以计算两个整数的最大公约数:
import { Function, Integer } from "@foundry/functions-api";
export class MyFunctions {
@Function()
public gcd(a: Integer, b: Integer): Integer {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}
}在 TypeScript v2 中,核心 TypeScript 逻辑完全相同,但你必须使用 @osdk/functions 包中的 Integer 类型:
import { Integer } from "@osdk/functions";
export default function gcd(a: Integer, b: Integer): Integer {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}请参阅类型参考,了解如何在 TypeScript v1 与 v2 函数的签名中导入与使用类型。
日期与时间戳
日期与时间戳
TypeScript v1 使用 @foundry/functions-api 包中的 LocalDate 与 Timestamp 类型处理时间数据。TypeScript v2 用 @osdk/functions 包中的 DateISOString 与 TimestampISOString 类型取代它们,这两个类型将日期与时间戳表示为 ISO 8601 ↗ 字符串。
TypeScript v2 函数可以使用 NPM 生态中任何可用的日期与时间戳库,例如 dayjs ↗、date-fns ↗ 与 luxon ↗。
生成本体 SDK
生成本体 SDK
TypeScript v2 函数通过 Ontology SDK 提供一流的查询与编辑 Ontology 的支持。与 TypeScript v1 一样,TypeScript v2 仓库允许你通过 Resource imports(资源导入) 侧边栏 导入 Ontology 实体。一旦你添加了对象类型与链接类型,系统会提示你创建 Ontology SDK 的初始版本。

选择 Create(创建),然后为 Ontology SDK 取一个名字。该名字在首个版本生成后无法更改。选择 Create new version(创建新版本) 以生成 Ontology SDK。

一旦 Ontology SDK 创建完成,你会看到一个将它安装到工作区的选项。选择 Install(安装) 会将 Ontology SDK 作为依赖添加到 package.json 文件中,使其可在 TypeScript 代码中使用。

查看侧边栏中的 Documentation(文档) 标签页,获取在 TypeScript 中使用你的 Ontology 的综合示例。
查询本体(重点)
查询本体(重点)
在 TypeScript v1 中,你必须从 @foundry/ontology-api 包导入 Objects 来执行对 Ontology 的搜索:
import { Function, Integer } from "@foundry/functions-api";
import { Objects } from "@foundry/ontology-api";
export class MyFunctions {
@Function()
public async countAircraft(): Promise<Integer> {
const count = await Objects.search().aircraft().count() ?? 0;
return count;
}
}在 TypeScript v2 中,你必须通过将 Ontology SDK 客户端指定为函数签名的第一个参数来访问它:
import { Aircraft } from "@ontology/sdk";
import { Client } from "@osdk/client";
import { Integer } from "@osdk/functions";
export default async function countAircraft(client: Client): Promise<Integer> {
const aircraft = await client(Aircraft).aggregate({
$select: {
$count: "unordered"
}
});
return aircraft.$count;
}本节其余部分将 TypeScript v1 的查询词汇映射到其 TypeScript v2 等价物。关于完整的 TypeScript v2 查询词汇,请参阅 TypeScript OSDK 参考。
你在两个版本中过滤、排序或聚合的每个属性,都必须在 Ontology Manager 中标记为 Searchable(可搜索)。Searchable 控制属性如何被索引,因此这一要求属于 Ontology 而非任何一个 SDK。变化之处在于你从何处发现:在 TypeScript v1 中,代码生成器会省略未标记属性的过滤、排序与聚合方法,因此使用它们会导致编译失败;而 Ontology SDK 在 .where()、$orderBy 与 .aggregate() 中接受对象类型上的任何属性。
:::callout{theme="warning" title="迁移前确认 Searchable"}
在迁移之前,请在 Ontology Manager 中确认你过滤、排序或聚合的每个属性都已标记为 Searchable。在 TypeScript v2 中,未标记的属性可以编译通过,因此问题只会在函数运行时出现:像 $containsAnyTerm 这样的全文谓词会返回一个空页而非报错,于是过滤器可能匹配不到任何内容却报告成功。
Filter operator mapping
在 TypeScript v1 中,.filter() 方法接受由你过滤的属性类型决定的过滤定义。TypeScript v2 用接受子句对象的单一 .where() 调用取代了那一族方法。下表将每个 TypeScript v1 过滤方法映射到其 TypeScript v2 where 子句键,以及它适用的属性类型。
TypeScript v2 的限制比 TypeScript v1 等价物更严格:一个地理空间属性只接受 $within、$intersects 与 $isNull,一个数组属性只接受 $contains 与 $isNull。关于它所记录的每个过滤器的形态,请参阅 TypeScript OSDK 参考中的 Filtering;它不涵盖 $within、$intersects 或 $interval。
| TypeScript v1 | TypeScript v2 where 子句键 | 适用于 |
|---|---|---|
.exactMatch(value) | $eq,或裸值 | 布尔、日期时间、数字、字符串 |
.exactMatch(...values) | $in: [...] | 布尔、日期时间、数字、字符串 |
Filters.not(exactMatch) | $ne | 布尔、日期时间、数字、字符串 |
.hasProperty() | $isNull: false | 数组、布尔、日期时间、地理点、地理形状、数字、字符串 |
Filters.not(hasProperty()) | $isNull: true | 数组、布尔、日期时间、地理点、地理形状、数字、字符串 |
.range().lt(x) | $lt | 日期时间、数字 |
.range().lte(x) | $lte | 日期时间、数字 |
.range().gt(x) | $gt | 日期时间、数字 |
.range().gte(x) | $gte | 日期时间、数字 |
.isTrue() / .isFalse() | $eq: true / $eq: false | 布尔 |
.matchAnyToken(...) | $containsAnyTerm | 字符串 |
.matchAllTokens(...) | $containsAllTerms | 字符串 |
.phrase(...) | $containsAllTermsInOrder | 字符串 |
.phrasePrefix(), .prefixOnLastToken() | $interval,搜索字符串放在 $match 中,并设 $prefixOnLastTerm: true | 字符串 |
.contains(...) | $contains,恰好接受一个内部过滤器 | 数组 |
.withinDistanceOf(), .withinPolygon(), .withinBoundingBox() | $within | 地理点、地理形状 |
.intersectsPolygon(), .intersectsBoundingBox() | $intersects | 地理形状 |
.doesNotIntersectPolygon(), .doesNotIntersectBoundingBox() | 包裹 $intersects 的 $not | 地理形状 |
.isPresent() | 无对应 where 子句键 | 链接 |
三个行为差异会改变转换后过滤器的形态。关于 TSv2 子句形态规则本身,请参阅 Filtering。
- 有界区间变为两个子句。 TypeScript v1 的
.range().gte(a).lte(b)链是一个单一调用,但 TypeScript v2 每个属性只接受一个运算符键,因此同一过滤器变为$and: [{ p: { $gte: a } }, { p: { $lte: b } }]。 - 多值
.contains()变为$or。 TypeScript v1 的.contains()接受多个值并匹配其中任意一个,而 TypeScript v2 的$contains恰好接受一个内部过滤器。 - 日期时间比较接受 ISO 8601 字符串,如
{ $gt: "2010-10-01T00:00:00Z" }。
Link traversal mapping
TypeScript v1 为每个对象接口上的每种链接类型生成一个字段,并为对象集上的每种链接类型生成一个 searchAround 方法。TypeScript v2 将每个链接的访问器嵌套在 $link 下,并用单一的 pivotTo() 方法取代整个 searchAround 家族。
| TypeScript v1 | TypeScript v2 |
|---|---|
SingleLink 字段,用 .get() 或 .getAsync() 读取 | $link.{linkApiName}.fetchOne(),或用 fetchOneWithErrors() 获得 { value } / { error } 包裹而非抛错。注意缺值时的行为变化:.get() 返回 undefined,而 fetchOne() 抛错,fetchOneWithErrors() 报告 { error },与其他任何失败无法区分 |
MultiLink 字段,用 .all() 或 .allAsync() 读取 | $link.{linkApiName},它已经是一个 ObjectSet,用 asyncIter() 迭代 |
对象集上的 searchAround<LinkApiName>() | pivotTo("<linkApiName>") |
不要从 searchAround 方法名推导链接 API 名称;方法名不能可靠地保留它。请改为查找链接 API 名称:在你生成的 TypeScript v2 SDK 中,对象类型的 $link 容器的键正是链接 API 名称,pivotTo() 原样接受该值。例如,API 名称为 toOtherObjectType 的链接用 pivotTo("toOtherObjectType") 遍历。
TypeScript v1 还限制了你能用从单个对象实例到达的链接做什么:一个 MultiLink 无法转换为对象集,因此你必须先从对象重建一个对象集。在 TypeScript v2 中你可以直接链式调用,因为多对多的 $link 项已经是一个 ObjectSet,且 pivotTo() 返回一个 ObjectSet。关于 TSv2 API 本身,请参阅 TypeScript OSDK 参考中的 Links。
Group-by strategy mapping
TypeScript v1 通过调用 .groupBy() 并传入由属性类型决定的分桶方法来进行聚合分组。TypeScript v2 在单次 .aggregate() 调用的 $groupBy 对象中,以值的形式提供相同的信息。下表将每个 TypeScript v1 分桶方法映射到其 TypeScript v2 $groupBy 值。
$ranges 接受一个二元组数组,$duration 接受一个 [值, 单位] 元组。范围在起点包含、终点不包含,与 TypeScript v1 一致。只有 "seconds"、"minutes"、"hours" 与 "days" 接受任意值;较粗的单位只接受 1。关于分组策略本身,请参阅 TypeScript OSDK 参考中的 Types of grouping。
| TypeScript v1 | TypeScript v2 $groupBy 值 |
|---|---|
.exactValues() | "exact" |
.exactValues({ maxBuckets: n }) | { $exactWithLimit: n } |
.topValues() | "exact" |
.byFixedWidth(50) | { $fixedWidth: 50 } |
.byRanges({ min: 0, max: 50 }, { min: 50, max: 100 }) | { $ranges: [[0, 50], [50, 100]] } |
.byYear() | { $duration: [1, "years"] } |
.byQuarter() | { $duration: [1, "quarters"] } |
.byMonth() | { $duration: [1, "months"] } |
.byWeek() | { $duration: [1, "weeks"] } |
.byDays(n) | { $duration: [n, "days"] } |
.byHours(n), .byMinutes(n), .bySeconds(n) | { $duration: [n, "hours"] }, { $duration: [n, "minutes"] }, { $duration: [n, "seconds"] } |
.segmentBy(...) | 同一 $groupBy 对象中的第二个键 |
每个精确值分组请求都带有一个最大桶数,且默认值在两个版本间不同:TypeScript v1 的 .topValues() 默认为 1,000,而 TypeScript v2 的 "exact" 默认为 10,000。只有当属性的不同值落在那个计数之内时,结果才准确。超出后,对象会被排除在返回的分组之外,聚合变为近似。平台在每次响应中都报告结果是准确还是近似,但 TypeScript OSDK 没有暴露该字段,因此在 TypeScript v2 函数内部,近似结果与精确结果读起来一样。对于高基数的属性,请用 { $exactWithLimit: n } 提高计数,或先用 .where() 收窄对象集。一个布尔属性最多有两个不同值,因此对它而言 "exact" 总是准确的。
Aggregation metric mapping
对对象集分组后,TypeScript v1 通过调用诸如 .count() 或 .average() 这样的聚合方法来计算指标。TypeScript v2 通过单次 .aggregate() 调用的 $select 对象选择指标。下表将每个 TypeScript v1 聚合方法映射到其 TypeScript v2 $select 键。
每个非 count 的键都是 "<propertyApiName>:<metric>" 形式的字符串,每个值都是排序指令:"unordered"、"asc" 或 "desc"。数值属性接受所有后缀;日期时间与时间戳属性只接受 min、max、approximateDistinct 与 exactDistinct;其他所有类型只接受两个去重计数后缀。关于聚合概念,请参阅 TypeScript OSDK 参考中的 Aggregations。
| TypeScript v1 | TypeScript v2 $select 键 |
|---|---|
.count() | $count: "unordered" |
.average(e => e.p) | "p:avg": "unordered" |
.max(e => e.p) | "p:max": "unordered" |
.min(e => e.p) | "p:min": "unordered" |
.sum(e => e.p) | "p:sum": "unordered" |
.cardinality(e => e.p) | "p:approximateDistinct": "unordered" |
| 无 TypeScript v1 等价物 | "p:exactDistinct": "unordered" |
一个差异会影响转换后调用的形态:.aggregate() 接受一个恰好有两个键的单一请求对象,必填的 $select 与可选的 $groupBy。没有 where 键,因此请在调用 .aggregate() 之前用链式 .where() 过滤对象集。
结果形态也随之改变,因此转换后的函数必须以不同方式读取自己的输出。关于 $select 指令、排序限制,以及如何读取一个分组结果,请参阅 TypeScript OSDK 参考中的 Aggregations。
Capabilities with no TypeScript v2 equivalent
一些 TypeScript v1 查询能力没有 TypeScript v2 对应物,因此在转换搜索或聚合之前要为它们做规划。
Filtering
- 链接存在性过滤没有 where 子句键。 在 TypeScript v1 中,
.isPresent()将一个对象集过滤为至少拥有一个给定类型链接对象、或(取反时)没有任何链接对象的对象。TypeScript v2 没有能做到这一点的$键。最接近的做法是派生属性:定义一个统计链接对象数量的属性,然后过滤该计数大于零。在依赖它之前,请针对你自己的数据测试;这是一种变通而非受支持的等价物。 Fuzziness(模糊度)编辑距离没有 TypeScript v2 形式。 TypeScript v2 的术语运算符$containsAnyTerm与$containsAllTerms接受一个普通的fuzzySearch布尔值,不提供编辑距离控制,因此Fuzziness.LEVENSHTEIN_ONE与Fuzziness.LEVENSHTEIN_TWO没有直接的 TypeScript v2 形式。$containsAllTermsInOrder根本不接受模糊选项。$interval键暴露了携带编辑距离的$fuzzy与$fuzziness子键,因此在使用前请针对你自己的数据测试这一构造。
Grouping
- 开放区间的桶已移除。 TypeScript v1 允许省略
min或max,得到一个从负无穷到max、或从min到正无穷的桶。TypeScript v2 的$ranges元组要求两个端点都存在。 Long属性无法在 TypeScript v2 中分组。 TypeScript v1 将Long列为可用于分组的数值类型之一,但 TypeScript v2 类型没有为Long属性提供$groupBy值。- 在 TypeScript v2 中按数组属性分组不受支持。 TypeScript v1 为数组属性提供与其元素类型相同的分桶方法。TypeScript v2 类型接受
$groupBy中的数组属性,因此这个错误能编译通过,但结果无法保证;请改为按标量属性分组。 - TypeScript v2 中没有
segmentBy。 TypeScript v1 在.groupBy()之后调用.segmentBy()来计算按两个属性分桶的三维聚合。TypeScript v2 的等价物是同一$groupBy对象中的第二个键,但它返回的并非相同形态:TypeScript v1 产生嵌套桶,而 TypeScript v2 返回一个扁平的行数组,每行携带一个$group对象,持有每个 group-by 键的值。因此,必须返回三维聚合的函数需要自己重建嵌套;关于每个版本期望的形态,请参阅聚合类型。
Aggregation metrics
- 对日期或时间戳求平均是 TypeScript v1 独有。 TypeScript v1 的
.average()接受时间戳与日期属性。TypeScript v2 在日期或时间戳属性上只提供min、max、approximateDistinct与exactDistinct,因此对其中之一既不可用avg也不可用sum。 - TypeScript v2 没有指标别名。 结果键总是从属性与指标派生,因此除
$count或"property:metric"字符串之外的任何$select键都是类型错误。
Ordering and loading
- TypeScript v2 中没有
.take()或.limit()。 排序不再是一个链式子句:它作为$orderBy进入fetchPage()或asyncIter()的 options 对象,你用同一 options 对象中的$pageSize限制结果数量。 - TypeScript v2 中没有
.all()。 TypeScript v1 的.all()与.allAsync()一次性物化整个对象集。TypeScript v2 用asyncIter()迭代,或用fetchPage()读取单页,如将对象加载到内存所述。 - 最近邻的边界扩大了。 TypeScript v1 将
k值限制为0 < K <= 100,而 TypeScript v2 的nearestNeighbors()方法接受 1 到 500 之间的numNeighbors。因此,处于其范围顶部的 TypeScript v1 搜索,在迁移后可请求的邻居数量是原来的五倍。 - 相关性排序只适用于最近邻搜索。 在 TypeScript v2 中,
$orderBy: "relevance"应用于nearestNeighbors()搜索,其中numNeighbors限制结果,每个返回的对象携带一个$score。它对基于 token 匹配的where子句无效,因此 TypeScript v1 的「用.matchAnyToken()过滤、按相关性排序、然后取前 N 个结果」模式没有 TypeScript v2 等价物。
对象标识
对象标识
TypeScript v1 通过对象的 rid、primaryKey 与 typeId 字段暴露其身份。TypeScript v2 为每个内置标识符字段加上 $ 前缀,以区别于对象自身的属性,并新增了 $objectSpecifier——一个编码了对象类型与主键的单字符串。因为 $rid 仅当读取通过 $includeRid: true 选择加入时才存在,所以在 TypeScript v2 中请使用 $objectSpecifier 而非 $rid 作为身份逻辑的基础。
Identifier reference
下表将每个 TypeScript v1 标识符与类型映射到其 TypeScript v2 等价物。
| TypeScript v1 | TypeScript v2 | 备注 |
|---|---|---|
obj.rid | obj.$rid | 仅当读取传入 $includeRid: true 时存在。 |
obj.primaryKey | obj.$primaryKey | 始终存在。 |
obj.typeId | obj.$apiName 或 obj.$objectType | 始终存在。两者都携带对象类型 API 名称;只有 $apiName 是字面量类型。 |
| 不可用 | obj.$objectSpecifier | 始终存在。字符串 "<apiName>:<primaryKey>"。 |
Employee | Osdk.Instance<Employee> | 已加载对象实例的类型。 |
OntologyObject | 无等价物 | 来自 @osdk/api 的 OsdkBase 是最接近的类型。 |
IsOntologyObject | 无等价物 | 已移除,无直接替代。 |
以对象为键的 FunctionsMap<T, V> | Record<ObjectSpecifier<T>, V> | 以标量为键的 FunctionsMap 变为普通的 Record<K, V>。参见 Object mappings。 |
迁移后,比较两个对象是否相等变得更简单。在 TypeScript v1 中你必须同时比较 typeId 与 primaryKey,因为主键只在单一对象类型内唯一。TypeScript v2 将两个值都编码进 $objectSpecifier,因此等价检查是一次单一的字符串比较,即便两个对象属于不同对象类型也保持正确:
function isEqual(o1: { $objectSpecifier: string }, o2: { $objectSpecifier: string }): boolean {
return o1.$objectSpecifier === o2.$objectSpecifier;
}关于两个版本中对象为键的映射的实例,请参阅类型参考中的 Map。关于两个例子的 TypeScript v1 形式,以及为什么对象相等需要小心的概念背景,请参阅 Object identifiers。
编辑本体
编辑本体
要在 TypeScript v1 中编写 Ontology 编辑函数,你必须用 @foundry/functions-api 包中的 @OntologyEditFunction() 装饰器标注它,并赋予它 void 返回类型。你还必须应用 @Edits 装饰器 来预先声明所有被编辑的对象类型,从而在函数支撑的动作被调用之前,就能对这些对象类型强制执行权限。
import { Edits, OntologyEditFunction } from "@foundry/functions-api";
import { Aircraft, Employee } from "@foundry/ontology-api";
export class MyOntologyEditFunctions {
@Edits(Aircraft, Employee)
@OntologyEditFunction()
public myFunction(aircraft: Aircraft, employee: Employee): void {
aircraft.businessCapacity = 3;
employee.department = "HR";
}
}在 TypeScript v2 中,你必须从 @osdk/functions 包导入 createEditBatch 函数来构造一个在执行期间使用的编辑存储。你必须使用 Edits 类型声明你的函数被允许编辑哪些实体。这在编译时强制类型安全;如果你试图编辑一个未被你的 Edits 类型覆盖的对象或链接类型,TypeScript 编译器会返回错误。
import { createEditBatch, Edits } from "@osdk/functions";
import { Aircraft, Employee } from "@ontology/sdk";
import { Client, Osdk } from "@osdk/client";
type OntologyEdit = Edits.Object<Aircraft> | Edits.Object<Employee>;
export default function myFunction(
client: Client,
aircraft: Osdk.Instance<Aircraft>,
employee: Osdk.Instance<Employee>
): OntologyEdit[] {
const batch = createEditBatch<OntologyEdit>(client);
batch.update(aircraft, { businessCapacity: 3 });
batch.update(employee, { department: "HR" });
return batch.getEdits();
}在 TypeScript v2 中,使用 Edits.Interface<MyInterface> 通过 Ontology 接口 属性创建、更新和删除对象。细节参见 Ontology edits。
在 TypeScript v1 中,编辑不会在函数执行期间应用到 Ontology。正如我们的编辑与对象搜索文档所述,对象与链接的变更只在函数执行完毕后、且仅当在 函数支撑的动作 内部被调用时,才会传播。
TypeScript v2 让这一行为更明确。你的函数不再隐式累积编辑,而是必须使用一个编辑批次跟踪它们,并在完成时返回。
有关受支持操作的完整列表,请参阅 TypeScript v2 文档中的 Ontology edits 一节。
TypeScript v2 还支持暂存写入,这是一种带有写后可读保障的替代执行模型。暂存写入函数使用 WriteableClient 而非 createEditBatch,且无需显式返回编辑。
生成对象唯一 ID
生成对象唯一 ID
要在 TypeScript v1 中为新创建的对象生成唯一 ID,请使用 @foundry/functions-utils 包中的 Uuid 工具。
import { Edits, OntologyEditFunction } from "@foundry/functions-api";
import { Uuid } from "@foundry/functions-utils";
import { FlightScenario, Objects } from "@foundry/ontology-api";
export class ExampleEditFunctions {
@Edits(FlightScenario)
@OntologyEditFunction()
public createFlightScenario(): void {
const scenario = Objects.create().flightScenarios(Uuid.random());
scenario.scenarioName = "New scenario";
}
}TypeScript v2 运行在完整的 Node.js 环境中,因此你可以改用 node:crypto 核心模块:
import { FlightScenario } from "@ontology/sdk";
import { Client } from "@osdk/client";
import { createEditBatch, Edits } from "@osdk/functions";
import { randomUUID } from "node:crypto";
type OntologyEdit = Edits.Object<FlightScenario>;
export default function createFlightScenario(client: Client): OntologyEdit[] {
const batch = createEditBatch<OntologyEdit>(client);
batch.create(FlightScenario, {
id: randomUUID(),
scenarioName: "New scenario",
});
return batch.getEdits();
}避免在函数体之外的模块顶层调用 randomUUID 或其他随机值生成器。TypeScript v2 函数使用预热(warm)调用,所有模块级代码在初始化时只求值一次,然后在后续调用中复用。这意味着模块级的 randomUUID 调用只会被求值一次,并为每次预热调用产生相同的值。请始终在函数体内部生成随机值以确保唯一性。
把对象加载进内存
把对象加载进内存
TypeScript v1 函数暴露 .all() 与 .allAsync() API,将特定类型的所有对象加载到内存中进行处理。然而,随着 Ontology 中对象数量的增长,这种方法可能导致高内存占用与较慢性能。
import { Edits, OntologyEditFunction } from "@foundry/functions-api";
import { Aircraft, Objects } from "@foundry/ontology-api";
export class MyFunctions {
@Edits(Aircraft)
@OntologyEditFunction()
public editAircraft(): void {
const aircraft = Objects.search().aircraft().all();
aircraft.forEach(a => {
a.arrived = true;
});
}
}TypeScript v2 函数通过 Ontology SDK 支持流式对象处理,避免了一次性将整个对象集保存在内存中的需要。我们建议尽可能采用这种方法。
import { Aircraft } from "@ontology/sdk";
import { Client } from "@osdk/client";
import { createEditBatch, Edits } from "@osdk/functions";
type OntologyEdit = Edits.Object<Aircraft>;
export default async function editAircraft(client: Client): Promise<OntologyEdit[]> {
const batch = createEditBatch<OntologyEdit>(client);
for await (const a of client(Aircraft).asyncIter()) {
batch.update(a, { arrived: true });
}
return batch.getEdits();
}如果数据规模不是问题,下面的替代方案会加载特定类型的所有对象:
import { Aircraft } from "@ontology/sdk";
import { Client } from "@osdk/client";
import { createEditBatch, Edits } from "@osdk/functions";
type OntologyEdit = Edits.Object<Aircraft>;
export default async function editAircraft(client: Client): Promise<OntologyEdit[]> {
const batch = createEditBatch<OntologyEdit>(client);
const aircraft = await Array.fromAsync(client(Aircraft).asyncIter());
aircraft.forEach(a => {
batch.update(a, { arrived: true });
});
return batch.getEdits();
}延伸阅读 · 相关页面
按主题横向跳转,不必顺着目录一篇篇读。
常见问题速答 · FAQ
关于「从 TypeScript v1 迁移到 v2」,读者最常问的几个问题。