使用typescript与neo4j
#网络开发人员 #typescript #node #neo4j

最近的5.2.0 Neo4j JavaScript Driver版本对打字稿用户具有一些重大改进。如此之多,以至于它启发了我写一篇文章。

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

一个有效的例子

例如,让我们从建议数据集中进行查询。假设我们想找到电影中出现的所有演员的清单。

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

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'))

由于结果中不存在something,因此将抛出一个Neo4jError

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

运行应用程序时,您最终会发现这一点,但是打字稿的全部要点是在开发过程中识别这些错误。

添加类型检查

为了防止这种类型的方案,我们现在可以使用接口来定义每个记录上可用的密钥。

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

  1. p-带有Person标签的Node,带有属性,包括nameborn
  2. r- RelationshipRelationship,带有属性,包括roles-一系列字符串
  3. m a Node带有Movie的标签。

neo4j-driver库导出了两个类型定义,即NodeRelationship,我们可以用来定义这些项目。

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

这两个类都接受仿制药来定义.identity的类型和值。

除非您在创建驱动程序时已设置disableLosslessIntegers选项,否则身份将是从neo4j-driver导出的Integer类型的实例。

人值可以定义为打字稿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()都接受接口,然后将类型检查添加到任何后续处理中。可以更新上面的示例将PersonActedInMovie接口传递到tx.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 suggests p, r and m as possible values

暗示特性

Typescript知道peoplePerson节点的数组,在键入时可以建议在接口中定义的属性。

VS Code suggests potential properties for the Person node

检查属性键

如果键在节点或关系的属性中不存在,那么Typescript将立即捡起并丢弃错误:

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

)

类型检查属性

typeScript现在也要注意每个属性的类型,因此,如果您尝试使用类型中未定义的值,那么Typescript将引发错误。

const names: string[] = people.map(
  person => person.properties.born
)
// Type 'number[]' is not assignable to type 'string[]'.

有兴趣了解更多吗?

如果您在了解有关neo4j的更多方面很有趣,我建议您结帐Beginners Neo4j Courses on GraphAcademy

如果您有兴趣了解更多信息,我目前正在为Neo4j GraphAcademy制作新的Neo4j & TypeScript course

您还可以在Building Neo4j Applications with Node.js
课程中了解有关using Neo4j in a Node.js project所需的所有信息,在此过程中,您将更深入地潜入驾驶员生命周期,并用Neo4j Sandbox instance的响应代替硬编码数据。

如果您有任何评论或问题,请随时使用reach out to me on Twitter