Docs
搜索⌘ K
  • 主页
  • 关于 The Graph
  • 支持的网络
  • 协议合约
  • 子图
    • 子流
      • 代币 API
        • AI Suite
          • 索引
            • 资源
              资源 > 迁移指南

              14 分钟

              AssemblyScript 迁移指南

              到目前为止,子图一直在使用 AssemblyScript 的第一个版本⁠ (v0.6) 之一。 最终,我们添加了对最新版本⁠ (v0.19.10) 的支持! 🎉

              这将使子图开发人员能够使用 AS 语言和标准库的更新特性。

              本指南适用于使用 0.22.0 版本以下的 graph-cli/graph-ts 的任何人。 如果您已经使用了高于(或等于)该版本号的版本,那么您已经在使用 AssemblyScript 的 0.19.10 版本 🙂。

              注意:从 0.24.0 开始,graph-node 可以支持这两个版本,具体取决于子图清单文件中指定的 apiVersion。

              特征

              新功能

              • TypedArrays 现在可以使用新的wrap静态方法⁠ (v0.8.1⁠)基于ArrayBuffers 构建
              • 新的标准库函数: String#toUpperCase, String#toLowerCase, String#localeCompare和TypedArray#set (v0.9.0⁠)
              • 增加了对 x instanceof GenericClass (v0.9.2⁠)的支持
              • 添加了 StaticArray<T>, 一种更高效的数组变体 (v0.9.3⁠)
              • 增加了 Array<T>#flat (v0.10.0⁠)
              • 在Number#toString (v0.10.1⁠)上实现了radix 参数
              • 添加了对浮点文字中的分隔符的支持 (v0.13.7⁠)
              • 添加了对一级函数的支持 (v0.14.0⁠)
              • 添加内置函数:i32/i64/f32/f64.add/sub/mul ( v0.14.13⁠)
              • 实现了Array/TypedArray/String#at (v0.18.2⁠)
              • 添加了对模板文字字符串的支持(v0.18.17⁠)
              • 添加了encodeURI(Component) 和 decodeURI(Component) (v0.18.27⁠)
              • 将 toString、toDateString 和 toTimeString 添加到 Date ([v0.18.29](https://github.com/⁠ AssemblyScript/assemblyscript/releases/tag/v0.18.29))
              • 为Date 添加了toUTCString(v0.18.30⁠)
              • 添加 nonnull/NonNullable 内置类型(v0.19.2⁠)

              优化

              • Math 函数,例如 exp、exp2、log、log2 和 pow 已替换为更快的变体 (v0.9.0⁠)
              • 些许优化了Math.mod (v0.17.1⁠)
              • 在 std Map 和 Set (v0.17.8⁠) 中缓存更多字段访问
              • 在 ipow32/64 (v0.18.2⁠)中优化二的幂运算

              其他

              • 现在可以从数组内容中推断出数组文字的类型(v0.9.0⁠)
              • 将 stdlib 更新为 Unicode 13.0.0 (v0.10.0⁠)

              如何升级?

              1. 将 subgraph.yaml 中的映射 apiVersion 更改为 0.0.9:
              1...2dataSources:3  ...4    mapping:5      ...6      apiVersion: 0.0.97      ...
              1. 通过运行以下命令,将您正在使用的 graph-cli 更新为 latest 版本:
              1# if you have it globally installed2npm install --global @graphprotocol/graph-cli@latest34# or in your subgraph if you have it as a dev dependency5npm install --save-dev @graphprotocol/graph-cli@latest
              1. 对 graph-ts 执行相同的操作,但不是全局安装,而是将其保存在您的主要依赖项中:
              1npm install --save @graphprotocol/graph-ts@latest
              1. 参考指南的其余部分修复语言更改带来的问题。
              2. 再次运行 codegen 和 deploy。

              重大变化

              可空性

              在旧版本的 AssemblyScript 上,您可以创建如下代码:

              1function load(): Value | null { ... }23let maybeValue = load();4maybeValue.aMethod();

              但是在较新的版本中,由于该值可以为空,因此需要您进行检查,如下所示:

              1let maybeValue = load()23if (maybeValue) {4  maybeValue.aMethod() // `maybeValue` is not null anymore5}

              或者像这样编写代码:

              1let maybeValue = load()! // breaks in runtime if value is null23maybeValue.aMethod()

              如果您不确定选择哪个,我们建议始终使用安全的方式。 如果该值不存在,您可能只想在您的子图处理程序中,尽早执行一个带有 return 的 if 语句进行检查。

              变量遮蔽

              在您可以进行 变量遮蔽⁠ 之前,这样的代码可以工作:

              1let a = 102let b = 203let a = a + b

              但是现在这不可能了,编译器会返回这个错误:

              1ERROR TS2451: Cannot redeclare block-scoped variable 'a'23 let a = a + b;4 ~~~~~~~~~~~~~5in assembly/index.ts(4,3)

              如果您有变量遮蔽的情况,则需要重命名重名变量。

              空值比较

              对子图进行升级后,有时您可能会遇到如下错误:

              1ERROR TS2322: Type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt | null' is not assignable to type '~lib/@graphprotocol/graph-ts/common/numbers/BigInt'.2     if (decimals == null) {3                     ~~~~4 in src/mappings/file.ts(41,21)

              要解决此问题,您只需将 if 语句更改为如下所示代码:

              1if (!decimals) {23  // or45  if (decimals === null) {

              如果您使用 != 而不是 ==,这同样适用。

              强制转换

              以前,进行强制转换的常用方法是使用 as关键字,如下所示:

              1let byteArray = new ByteArray(10)2let uint8Array = byteArray as Uint8Array // equivalent to: <Uint8Array>byteArray

              但是,这只适用于两种情况:

              • 原始类型转换(在u8, i32, bool等类型之间; 例如: let b: isize = 10; b as usize);
              • 在类继承时向上转换(子类 → 超类)

              例子:

              1// primitive casting2let a: usize = 103let b: isize = 54let c: usize = a + (b as usize)
              1// upcasting on class inheritance2class Bytes extends Uint8Array {}34let bytes = new Bytes(2)5// <Uint8Array>bytes // same as: bytes as Uint8Array

              在两种情况下,您可能希望进行类型转换,但使用 as/<T>var 并不安全:

              • 在类继承时向下转换(超类 → 子类)
              • 在共享超类的两种类型之间
              1// downcasting on class inheritance2class Bytes extends Uint8Array {}34let uint8Array = new Uint8Array(2)5// <Bytes>uint8Array // breaks in runtime :(
              1// between two types that share a superclass2class Bytes extends Uint8Array {}3class ByteArray extends Uint8Array {}45let bytes = new Bytes(2)6// <ByteArray>bytes // breaks in runtime :(

              对于这些情况,您可以使用 changetype<T> 函数:

              1// downcasting on class inheritance2class Bytes extends Uint8Array {}34let uint8Array = new Uint8Array(2)5changetype<Bytes>(uint8Array) // works :)
              1// between two types that share a superclass2class Bytes extends Uint8Array {}3class ByteArray extends Uint8Array {}45let bytes = new Bytes(2)6changetype<ByteArray>(bytes) // works :)

              如果您只想去掉可空性,您可以继续使用 as 运算符(或 <T>variable),但请确保您知道该值不会为空, 否则程序会出现问题。

              1// remove nullability2let previousBalance = AccountBalance.load(balanceId) // AccountBalance | null34if (previousBalance != null) {5  return previousBalance as AccountBalance // safe remove null6}78let newBalance = new AccountBalance(balanceId)

              对于可空性情况,我们建议查看可空性检查功能⁠,它会让您的代码更简洁 🙂

              我们还在某些类型中添加了一些静态方法来简化转换,它们是:

              • Bytes.fromByteArray
              • Bytes.fromUint8Array
              • BigInt.fromByteArray
              • ByteArray.fromBigInt

              使用属性访问进行可空性检查

              要使用 可空性检查功能⁠,您可以使用 if 语句或三元运算符(? 和 :),如下所示:

              1let something: string | null = 'data'23let somethingOrElse = something ? something : 'else'45// or67let somethingOrElse89if (something) {10  somethingOrElse = something11} else {12  somethingOrElse = 'else'13}

              但是,这仅在您对变量执行 if / 三元组而不是属性访问时才有效,如下所示:

              1class Container {2  data: string | null3}45let container = new Container()6container.data = 'data'78let somethingOrElse: string = container.data ? container.data : 'else' // doesn't compile

              输出此错误:

              1ERROR TS2322: Type '~lib/string/String | null' is not assignable to type '~lib/string/String'.23   let somethingOrElse: string = container.data ? container.data : "else";4                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

              要解决此问题,您可以为该属性访问创建一个变量,以便编译器可以执行可空性检查:

              1class Container {2  data: string | null3}45let container = new Container()6container.data = 'data'78let data = container.data910let somethingOrElse: string = data ? data : 'else' // compiles just fine :)

              具有属性访问的运算符重载

              如果您尝试将可空类型(来自属性访问)与不可空类型相加,AssemblyScript 编译器不会给出编译时错误警告其中一个值可以为空,它只是静默编译,这会导致代码在运行时可能出现问题。

              1class BigInt extends Uint8Array {2  @operator('+')3  plus(other: BigInt): BigInt {4    // ...5  }6}78class Wrapper {9  public constructor(public n: BigInt | null) {}10}1112let x = BigInt.fromI32(2)13let y: BigInt | null = null1415x + y // give compile time error about nullability1617let wrapper = new Wrapper(y)1819wrapper.n = wrapper.n + x // doesn't give compile time errors as it should

              我们为此在 AssemblyScript 编译器上提出了一个 issue,但现在如果您在子图映射中执行此类操作,您应该在之前进行空值检查。

              1let wrapper = new Wrapper(y)23if (!wrapper.n) {4  wrapper.n = BigInt.fromI32(0)5}67wrapper.n = wrapper.n + x // now `n` is guaranteed to be a BigInt

              值初始化

              如果您有这样的代码:

              1var value: Type // null2value.x = 103value.y = 'content'

              代码将编译成功,但在运行时会出现问题,这是因为值尚未初始化,因此请确保您的子图已初始化变量的值,如下所示:

              1var value = new Type() // initialized2value.x = 103value.y = 'content'

              此外,如果您在 GraphQL 实体中有可为空的属性,如下所示:

              1type Total @entity {2  id: Id!3  amount: BigInt4}

              同时,您有类似这样的代码:

              1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest')5}67total.amount = total.amount + BigInt.fromI32(1)

              您需要确保初始化 total.amount 值,因为如果您尝试像最后一行代码一样求和,程序将崩溃。 所以你要么先初始化它:

              1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest')5  total.amount = BigInt.fromI32(0)6}78total.tokens = total.tokens + BigInt.fromI32(1)

              或者您可以更改您的 GraphQL 模式,不给此属性赋予可为空的类型,然后您在 codegen 步骤中将其初始化为零 😉

              1type Total @entity {2  id: Bytes!3  amount: BigInt!4}
              1let total = Total.load('latest')23if (total === null) {4  total = new Total('latest') // already initializes non-nullable properties5}67total.amount = total.amount + BigInt.fromI32(1)

              类属性初始化

              如果您导出任何具有其他类(由您或标准库声明)的属性的类,如下所示:

              1class Thing {}23export class Something {4  value: Thing5}

              编译器会报错,因为您需要为类属性添加初始化程序,或者添加 ! 运算符:

              1export class Something {2  constructor(public value: Thing) {}3}45// or67export class Something {8  value: Thing910  constructor(value: Thing) {11    this.value = value12  }13}1415// or1617export class Something {18  value!: Thing19}

              数组初始化

              Array 类仍然接受一个数字来初始化列表的长度,但是您应该小心,因为像.push的操作实际上会增加大小,而不是添加到开头,例如:

              1let arr = new Array<string>(5) // ["", "", "", "", ""]23arr.push('something') // ["", "", "", "", "", "something"] // size 6 :(

              根据您使用的类型,例如可以为空的类型,以及访问它们的方式,您可能会遇到类似下面这样的运行时错误:

              1ERRO Handler 由于执行失败而跳过,错误: 映射在 ~ lib/array.ts,第110行,第40列中止,并且带有消息: 如果 array 是漏洞 wasm 反向跟踪,那么 Element type 必须为 null: 0:0x19c4-<unknown>!~lib/@graphprotocol/graph-ts/index/format         1: 0x1e75 - <unknown>!~lib/@graphprotocol/graph-ts/common/collections/Entity#constructor        2: 0x30b9 - <unknown>!node_modules/@graphprotocol/graph-ts/global/global/id_of_type

              要想真正在开始的时候推入,你应该将 Array 初始化为大小为零,如下所示:

              1let arr = new Array<string>(0) // []23arr.push('something') // ["something"]

              或者,你可以通过索引对其进行改变:

              1let arr = new Array<string>(5) // ["", "", "", "", ""]23arr[0] = 'something' // ["something", "", "", "", ""]

              GraphQL 模式

              这不是一个直接的 AssemblyScript 更改,但是您可能需要更新 schema.Graphql 文件。

              现在,您不再能够在类型中定义属于非空列表的字段。如果您有这样的模式:

              1type Something @entity {2  id: Bytes!3}45type MyEntity @entity {6  id: Bytes!7  invalidField: [Something]! # no longer valid8}

              您必须向 List 类型的成员添加一个! ,如下所示:

              1type Something @entity {2  id: Bytes!3}45type MyEntity @entity {6  id: Bytes!7  invalidField: [Something!]! # valid8}

              AssemblyScript 版本之间的可空性差异导致了这种改变, 并且这也与 src/generated/schema.ts文件(默认路径,您可能已更改)有关。

              其他

              • 将 Map#set 和 Set#add 与规范对齐,返回 this ([v0.9.2](https://github.com/AssemblyScript⁠ /assemblyscript/releases/tag/v0.9.2))
              • 数组不再继承自 ArrayBufferView,并且现在是完全不同的 (v0.10.0⁠)
              • 从对象字面初始化的类不能再定义构造函数(v0.10.0⁠)
              • 如果两个操作数都是整数,则 ** 二元运算的结果现在是公分母整数。 以前,结果是一个浮点数,就像调用 Math/f.pow (v0.11.0⁠)
              • 在转换为 bool 时强制 NaN 为 false ([v0.14.9](https://github.com/AssemblyScript/assemblyscript/releases/tag⁠ /v0.14.9))
              • 当移动 i8/u8 或 i16/u16 类型的小整数值时,只有 4 个 RHS 值的最低有效位中的 3 个会影响结果,类似于 i32.shl 的结果仅受 RHS 值的 5 个最低有效位影响。 示例:someI8 << 8 以前生成值 0,但现在由于将 RHS 屏蔽为8 & 7 = 0 (3 比特), 而生成 someI8(v0.17.0⁠)
              • 修复了大小不同时关系字符串比较的错误 (v0.17.8⁠)
              ⁠在GitHub上编辑⁠

              策展GraphQL验证迁移指南
              在此页面上
              • 特征
              • 新功能
              • 优化
              • 其他
              • 如何升级?
              • 重大变化
              • 可空性
              • 变量遮蔽
              • 空值比较
              • 强制转换
              • 使用属性访问进行可空性检查
              • 具有属性访问的运算符重载
              • 值初始化
              • 类属性初始化
              • 数组初始化
              • GraphQL 模式
              • 其他
              The GraphStatusTestnetBrand AssetsForum安全Privacy PolicyTerms of Service