Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@brakebein/nest-neo4j

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@brakebein/nest-neo4j

Neo4j integration for NestJS

  • 1.3.0
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

Nest Logo Neo4j Logo

Nest Neo4j

This repository provides Neo4j integration for NestJS wrapping the official neo4j-driver.

It is a fork of adam-cowley/nest-neo4j with some changes:

  • the queried records are extracted to a simplified format
  • non-standard properties (e.g. dates) are converted
  • updated dependencies

Installation

$ npm install @brakebein/nest-neo4j

Setup

Register the Neo4j Module in your application using the forRoot method, passing the Neo4j connection information as an object. Specific Neo4j settings (refer to neo4j-driver) can be passed via options.

import { Module } from '@nestjs/common';
import { Neo4jModule } from '@brakebein/nest-neo4j';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    Neo4jModule.forRoot({
      scheme: 'neo4j',
      host: 'localhost',
      port: 7687,
      username: 'neo4j',
      password: 'neo',
      options: {
        disableLosslessIntegers: true,
      },
      verifyConnectionTimout: 60000,
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Alternatively, you can use forRootAsync to access information dynamically via ConfigService:

import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Neo4jModule } from '@brakebein/nest-neo4j';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    Neo4jModule.forRootAsync({
      useFactory: async (configService: ConfigService) => ({
        scheme: configService.get('NEO4J_SCHEME'),
        host: configService.get('NEO4J_HOST'),
        port: configService.get('NEO4J_PORT'),
        username: configService.get('NEO4J_USERNAME'),
        password: configService.get('NEO4J_PASSWPRD'),
        database: configService.get('NEO4J_DATABASE'),
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

If the Neo4j instance is unavailable, connection is not possible. Driver instantiation will be re-invoked a few times before throwing an error (useful in cases like server startup when node application is live earlier than the Neo4j database instance). Set verifyConnectionTimeout to increase the timeout before throwing an error.

Querying Neo4j

The Neo4jService is @Injectable, so can be passed into any constructor:

import { Neo4jService } from '@brakebein/nest-neo4j';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly neo4j: Neo4jService,
  ) {}

  @Get()
  async getHello(): Promise<any> {
    const results = await this.neo4j.read(`MATCH (n) RETURN count(n) AS count`);

    return `There are ${results[0].count} nodes in the database`;
  }
}

Methods

The query results returned by neo4j-driver are mapped to objects that correlate with identifiers within the RETURN clause and the node's properties. To access the raw query results, use the respective methods, e.g. .readRaw().

.read(cypher: string, params?: Record<string, any>, database?: string)

A very simple read transaction that expects a cypher statement and (optionally) query parameters.

Returns an array of objects, where the object's property names correlate with identifiers within the RETURN clause.

const query = `
  MATCH (p:Person {name: $name})-[:HAS_ADDRESS]->(add:Address)
  RETURN p.name AS name, add AS address
`;

const params = {
  name: 'Alex'
};

const results = await this.neo4j.read(query, params);
console.log(results);

// console.log(results)
// [
//   {
//     name: 'Alex',
//     address: {
//       ZIP: '10178',
//       number: '1',
//       town: 'Berlin',
//       street: 'Alexanderplatz'
//     }
//   }
// ]

Use .readRaw() to get the raw query results.

.write(cypher: string, params?: Record<string, any>, database?: string)

Very similar to .read() (see for details) except that it expects a cypher statement that modifies the database.

Use .writeRaw() to get the raw query results.

.multipleStatements(statements: { statement: string; parameters: Record<string, any> }[])

Execute multiple cypher queries within one transaction. A fail of one statement will lead to the rollback of the whole transaction.

Returns an array of arrays of objects (similar to .read() or .write()).

const statements = [{
  statement: `CREATE ...`,
  parameters: {}
}, {
  statement: `MATCH ... CREATE (n:Node $map) ...`,
  parameters: { map: { value: 'foo' } }
}];

const results = await this.neo4j.multipleStatements(statements);
// handle results

Use .multipleStatementsRaw() to get an array of the raw query results.

.getDriver()

Get the driver instance to access the full API of neo4j-driver.

.getConfig()

Get configuration as provided with Neoj4Module.

.getReadSession(database?: string)

Acquire a READ session to execute, e.g., explicit transactions.

.getWriteSession(database?: string)

Acquire a WRITE session to execute, e.g., explicit transactions.

.extractRecords<T = any>(data: Record[]): T[]()

Used internally to extract and convert the returned records by neo4j-driver to a more simplified format. It converts non-standard values, like date, time, etc., to strings as well as Neo4j integers, if they are outside the safe range.

Takes an array of Neo4j records Record[] and returns an array of objects.

import { Neo4jService } from './neo4j.service';

const query = `
  MATCH (p:Person {name: "Alex"})-[:HAS_ADDRESS]->(add:Address)
  RETURN p.name AS name, add AS address
`;

// query results returned by neo4j-driver
// {
//   records: [
//     Record {
//       keys: [ 'name', 'address' ],
//       length: 2,
//       _fields: [
//         'Alex',
//         Node {
//           identity: 1,
//           labels: [ 'Address' ],
//           properties: {
//             ZIP: '10178',
//             number: '1',
//             town: 'Berlin',
//             street: 'Alexanderplatz'
//           }
//         }
//       ]
//       _fieldLookup: { name: 0, address: 1 }
//     }
//   ],
//   summary: ResultSummary {...}
// }

extractRecords(queryResults.records);

// simplified records returned by neo4j-request
// {
//   name: 'Alex',
//   address: {
//     ZIP: '10178',
//     number: '1',
//     town: 'Berlin',
//     street: 'Alexanderplatz'
//   }
// }
.removeEmptyArrays<T>(data: T[], arrayKey: string, checkKey: string): T[]

Look for empty arrays returned by Neo4j and clean them, if there is null inside.

Sometimes, if the cypher query contains OPTIONAL MATCH node in combination with collect({key: node.value}) AS values, the resulting array may be filled with one object with null values: [{key: null}]. This method reduces the array to [] by calling removeEmptyArrays(data, 'values', 'key').

const query = `
  MATCH (p:Person {name: "Alex"})-[:HAS_ADDRESS]->(add:Address)
  OPTIONAL MATCH (p)-[:HAS_FRIEND]->(f:Person)-[:HAS_ADDRESS]->(fAddr:Address)
  RETURN p.name AS name,
         add AS address,
         collect({name: f.name, address: fAddr}) AS friends
`;

const results = await this.neo4j.read(query);
console.log(results);

// [
//   {
//     name: 'Alex',
//     address: {
//       ZIP: '10178',
//       number: '1',
//       town: 'Berlin',
//       street: 'Alexanderplatz'
//     },
//     friends: [ { address: null, name: null } ]
//   }
// ]

const resultsCleaned = this.neo4j.removeEmptyArrays(results, 'friends', 'name');
console.log(resultsCleaned);

// [
//   {
//     name: 'Alex',
//     address: {
//       ZIP: '10178',
//       number: '1',
//       town: 'Berlin',
//       street: 'Alexanderplatz'
//     },
//     friends: []
//   }
// ]

Keywords

FAQs

Package last updated on 08 Dec 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc