将 TypeScript 与 Neo4j 一起使用


现在可以使用接口来定义 Cypher 查询返回的记录类型,从而在处理结果时提供类型检查和类型提示的额外好处。

一个工作的例子

例如,让我们从建议数据集中获取一个查询。假设我们想找到电影中出现过的所有演员的列表。

要找到它,我们需要创建一个新的驱动程序实例,打开一个新会话,然后使用该函数发送 Cypher 语句并等待结果。executeRead()

async function main() {
  // Create a Driver Instance
  const driver = neo4j.driver(
    'neo4j://localhost:7687',
    neo4j.auth.basic('neo4j', 'letmein!')
  )

  // Open a new Session
  const session = driver.session()

  try {
    // Execute a Cypher statement in a Read Transaction
    const res = await session.executeRead(tx => tx.run(`
      MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title})
      RETURN p, r, m
    `, { title: 'Pulp Fiction' }))

    const people = res.records.map(row => row.get('p'))

    console.log(people)
  }
  finally {
    // Close the Session
    await session.close()
  }
}

足够简单,就像所有完美的开发人员一样,我们永远不会遇到以这种方式编写代码的任何问题。

另一方面,如果有人碰巧在行中输入拼写错误或尝试使用结果中未返回的值,则驱动程序将被写入以引发错误。res.records.map(row => row.get('p')).get()

假设该行更改为:

const people = res.records.map(row => row.get('something'))

由于结果中不存在,因此将抛出:somethingNeo4jError

Neo4jError: This record has no field with key 'something', 
available key are: [p,r,m].

当你运行应用程序时,你最终会发现这一点,但TypeScript的全部意义是在开发过程中识别这些错误。

添加类型检查

为了防止这种情况,我们现在可以使用接口来定义每条记录上可用的键。

在上述查询的情况下,我们有三个值:

  1. p– 带有标签的标签,其属性包括和NodePersonnameborn
  2. r– 具有属性的类型包括 – 字符串数组RelationshipACTED_INroles
  3. ma 标签为 .NodeMovie

该库导出两个类型定义,以及 ,我们可以用来定义这些项。neo4j-driverNodeRelationship

import neo4j, { Node, Relationship } from 'neo4j-driver'

这两个类都接受泛型来定义 的类型以及值上保存的属性。.identity

除非在创建驱动程序时设置了该选项,否则标识将是从 导出的类型实例。disableLosslessIntegersIntegerneo4j-driver

人员值可以定义为 打字稿 。type

import { Integer } from 'neo4j-driver'

interface PersonProperties {
  tmdbId: string;
  name: string;
  born: number; // Year of birth
}

type Person = Node<Integer, PersonProperties>

或者,对于更简洁的示例,可以直接在第二个泛型中定义属性:

type Movie = Node<Integer, {
  tmdbId: string;
  title: string;
  rating: number;
}>

关系几乎相同,但改用类型。Relationship

type ActedIn = Relationship<Integer, {
  roles: string[];
}>

这些类型可以在接口中组合,以表示结果中的每条记录:

interface PersonActedInMovie {
  p: Person;
  r: ActedIn;
  m: Movie;
}

和 都接受接口,并将类型检查添加到任何后续处理中。可以更新上面的示例以将接口传递给方法调用。session.run()tx.run()PersonActedInMovietx.run()

// Execute a Cypher statement in a Read Transaction
const res = await session.executeRead(tx => tx.run<PersonActedInMovie>(`
  MATCH (p:Person)-[r:ACTED_IN]->(m:Movie {title: $title})
  RETURN p, r, m
`, { title: 'Pulp Fiction' }))

类型检查在操作

由于记录形状已定义,TypeScript 现在将在编写代码时对其进行验证并提供建议。

建议记录键

现在,在调用该方法时提供了建议。record.get()

VS Code 建议 p、r 和 m 作为可能的值

建议属性

TypeScript 知道这是一个节点数组,可以在键入时建议界面中定义的属性。peoplePerson

VS Code 建议 Person 节点的潜在属性

检查属性键

如果节点或关系的属性中不存在键,TypeScript 将立即选取该键并抛出错误:

const names = people.map(
  person => person.properties.foo 
  // Property 'foo' does not exist
  // on type 'PersonProperties' 

)

类型检查属性

TypeScript 现在还可以识别每个属性的类型,因此如果您尝试使用类型中未定义的值,TypeScript 将引发错误。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/292474.html

(0)
上一篇 2022年11月1日
下一篇 2022年11月1日

相关推荐

发表回复

登录后才能评论