{"id":18830930,"url":"https://github.com/nhogs/nestjs-neo4j","last_synced_at":"2025-08-15T19:34:03.259Z","repository":{"id":37611390,"uuid":"444354246","full_name":"Nhogs/nestjs-neo4j","owner":"Nhogs","description":"Neo4j module for Nestjs","archived":false,"fork":false,"pushed_at":"2024-04-24T21:35:47.000Z","size":563,"stargazers_count":28,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-01T11:22:11.357Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nhogs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["nhogs"]}},"created_at":"2022-01-04T09:11:14.000Z","updated_at":"2024-06-21T02:36:29.632Z","dependencies_parsed_at":"2024-04-24T22:31:15.691Z","dependency_job_id":"6890244e-e742-4be6-95b6-01c7265dcf75","html_url":"https://github.com/Nhogs/nestjs-neo4j","commit_stats":{"total_commits":63,"total_committers":3,"mean_commits":21.0,"dds":"0.19047619047619047","last_synced_commit":"3681a92b7a367031c9173dfb4c87f1a1f93a4447"},"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nhogs%2Fnestjs-neo4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nhogs%2Fnestjs-neo4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nhogs%2Fnestjs-neo4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nhogs%2Fnestjs-neo4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nhogs","download_url":"https://codeload.github.com/Nhogs/nestjs-neo4j/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223619745,"owners_count":17174416,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T01:51:21.115Z","updated_at":"2024-11-08T01:51:21.746Z","avatar_url":"https://github.com/Nhogs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/nhogs"],"categories":[],"sub_categories":[],"readme":"\u003ca href=\"https://nhogs.com\"\u003e\u003cimg src=\"https://nhogs.com/nhogs_64.png\" align=\"right\" alt=\"nhogs-logo\" title=\"NHOGS Interactive\"\u003e\u003c/a\u003e\n\n# @nhogs/nestjs-neo4j\n\n## Description\n\n[Neo4j](https://neo4j.com/) module for [Nest.js](https://github.com/nestjs/nest).\n\n[![e2e-test](https://github.com/nhogs/nestjs-neo4j/actions/workflows/e2e-test.yml/badge.svg)](https://github.com/Nhogs/nestjs-neo4j/actions/workflows/e2e-test.yml)\n[![Docker-tested-version](https://img.shields.io/badge/E2e%20tests%20on-neo4j%3A5.19.0--enterprise-blue?logo=docker)](https://registry.hub.docker.com/_/neo4j/tags)\n[![Maintainability](https://api.codeclimate.com/v1/badges/2de17798cf9b4d9cfd83/maintainability)](https://codeclimate.com/github/Nhogs/nestjs-neo4j/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/2de17798cf9b4d9cfd83/test_coverage)](https://codeclimate.com/github/Nhogs/nestjs-neo4j/test_coverage)\n\n### Peer Dependencies\n\n[![npm peer dependency version NestJS)](https://img.shields.io/npm/dependency-version/@nhogs/nestjs-neo4j/peer/@nestjs/core?label=Nestjs\u0026logo=nestjs\u0026logoColor=e0234e)](https://github.com/nestjs/nest)\n[![npm peer dependency version neo4j-driver)](https://img.shields.io/npm/dependency-version/@nhogs/nestjs-neo4j/peer/neo4j-driver?label=neo4j-driver\u0026logo=neo4j)](https://github.com/neo4j/neo4j-javascript-driver)\n\n## Installation\n\n[![npm](https://img.shields.io/npm/v/@nhogs/nestjs-neo4j?logo=npm)](https://www.npmjs.com/package/@nhogs/nestjs-neo4j)\n\n```bash\n$ npm i --save @nhogs/nestjs-neo4j\n```\n\n## Usage\n\n### In static module definition:\n\n```typescript\n@Module({\n  imports: [\n    Neo4jModule.forRoot({\n      scheme: 'neo4j',\n      host: 'localhost',\n      port: '7687',\n      database: 'neo4j',\n      username: 'neo4j',\n      password: 'test',\n      global: true, // to register in the global scope\n    }),\n    CatsModule,\n  ],\n})\nexport class AppModule {}\n```\n\n### In async module definition:\n\n```typescript\n@Module({\n  imports: [\n    Neo4jModule.forRootAsync({\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (configService: ConfigService): Neo4jConfig =\u003e ({\n        scheme: configService.get('NEO4J_SCHEME'),\n        host: configService.get('NEO4J_HOST'),\n        port: configService.get('NEO4J_PORT'),\n        username: configService.get('NEO4J_USERNAME'),\n        password: configService.get('NEO4J_PASSWORD'),\n        database: configService.get('NEO4J_DATABASE'),\n      }),\n      global: true,\n    }),\n    PersonModule,\n    ConfigModule.forRoot({\n      envFilePath: './test/src/.test.env',\n    }),\n  ],\n})\nexport class AppAsyncModule {}\n```\n\n### [🔗 Neo4jService](/lib/service/neo4j.service.ts) :\n\n```typescript\n@Injectable()\n/** See https://neo4j.com/docs/api/javascript-driver/current/ for details ...*/\nexport class Neo4jService implements OnApplicationShutdown {\n  constructor(\n    @Inject(NEO4J_CONFIG) private readonly config: Neo4jConfig,\n    @Inject(NEO4J_DRIVER) private readonly driver: Driver,\n  ) {}\n\n  /** Verifies connectivity of this driver by trying to open a connection with the provided driver options...*/\n  verifyConnectivity(options?: { database?: string }): Promise\u003cServerInfo\u003e {...}\n\n  /** Regular Session. ...*/\n  getSession(options?: SessionOptions): Session {...}\n\n  /** Reactive session. ...*/\n  getRxSession(options?: SessionOptions): RxSession {...}\n\n  /** Run Cypher query in regular session and close the session after getting results. ...*/\n  run(\n    query: Query,\n    sessionOptions?: SessionOptions,\n    transactionConfig?: TransactionConfig,\n  ): Promise\u003cQueryResult\u003e {...}\n\n  /** Run Cypher query in reactive session. ...*/\n  rxRun(\n    query: Query,\n    sessionOptions?: SessionOptions,\n    transactionConfig?: TransactionConfig,\n  ): RxResult {...}\n\n  /** Returns constraints as runnable Cypher queries defined with decorators on models. ...*/\n  getCypherConstraints(label?: string): string[] {...}\n\n  onApplicationShutdown() {\n    return this.driver.close();\n  }\n}\n```\n\n```typescript\n/**\n * Cat Service example\n */\n\n@Injectable()\nexport class CatService {\n  constructor(private readonly neo4jService: Neo4jService) {}\n\n  async create(cat: Cat): Promise\u003cCat\u003e {\n    const queryResult = await this.neo4jService.run(\n      {\n        cypher: 'CREATE (c:`Cat`) SET c=$props RETURN properties(c) AS cat',\n        parameters: {\n          props: cat,\n        },\n      },\n      { write: true },\n    );\n\n    return queryResult.records[0].toObject().cat;\n  }\n\n  async findAll(): Promise\u003cCat[]\u003e {\n    return (\n      await this.neo4jService.run({\n        cypher: 'MATCH (c:`Cat`) RETURN properties(c) AS cat',\n      })\n    ).records.map((record) =\u003e record.toObject().cat);\n  }\n}\n```\n\n### Run with reactive session\n\n```typescript\nneo4jService\n  .rxRun({ cypher: 'MATCH (n) RETURN count(n) AS count' })\n  .records()\n  .subscribe({\n    next: (record) =\u003e {\n      console.log(record.get('count'));\n    },\n    complete: () =\u003e {\n      done();\n    },\n  });\n```\n\n### Define constraints with decorators on Dto\n\nhttps://neo4j.com/docs/cypher-manual/current/constraints/\n\n- @NodeKey():\n  - Node key constraints\n- @Unique():\n  - Unique node property constraints\n- @NotNull():\n  - Node property existence constraints\n  - Relationship property existence constraints\n\n[🔗 Constraint decorators - source code](/lib/decorator/constraint.decorator.ts)\n\n```typescript\n@Node({ label: 'Person' })\nexport class PersonDto {\n  @NodeKey({ additionalKeys: ['firstname'] })\n  name: string;\n\n  @NotNull()\n  firstname: string;\n\n  @NotNull()\n  @Unique()\n  surname: string;\n\n  @NotNull()\n  age: number;\n}\n\n@Relationship({ type: 'WORK_IN' })\nexport class WorkInDto {\n  @NotNull()\n  since: Date;\n}\n```\n\nWill generate the following constraints:\n\n```cypher\nCREATE CONSTRAINT `person_name_key` IF NOT EXISTS FOR (p:`Person`) REQUIRE (p.`name`, p.`firstname`) IS NODE KEY\nCREATE CONSTRAINT `person_firstname_exists` IF NOT EXISTS FOR (p:`Person`) REQUIRE p.`firstname` IS NOT NULL\nCREATE CONSTRAINT `person_surname_unique` IF NOT EXISTS FOR (p:`Person`) REQUIRE p.`surname` IS UNIQUE\nCREATE CONSTRAINT `person_surname_exists` IF NOT EXISTS FOR (p:`Person`) REQUIRE p.`surname` IS NOT NULL\nCREATE CONSTRAINT `person_age_exists` IF NOT EXISTS FOR (p:`Person`) REQUIRE p.`age` IS NOT NULL\n\nCREATE CONSTRAINT `work_in_since_exists` IF NOT EXISTS FOR ()-[p:`WORK_IN`]-() REQUIRE p.`since` IS NOT NULL\n```\n\n### Extends Neo4j Model Services helpers to get basic CRUD methods for node or relationships:\n\n```mermaid\nclassDiagram\nclass Neo4jModelService~T~\n\u003c\u003cabstract\u003e\u003e Neo4jModelService\nclass Neo4jNodeModelService~N~\n\u003c\u003cabstract\u003e\u003e Neo4jNodeModelService\nclass Neo4jRelationshipModelService~R~\n\u003c\u003cabstract\u003e\u003e Neo4jRelationshipModelService\nNeo4jModelService : string label*\nNeo4jModelService : runCypherConstraints()\nNeo4jModelService \u003c|--Neo4jNodeModelService\nNeo4jNodeModelService : create()\nNeo4jNodeModelService : merge()\nNeo4jNodeModelService : update()\nNeo4jNodeModelService : delete()\nNeo4jNodeModelService : findAll()\nNeo4jNodeModelService : findBy()\nNeo4jModelService \u003c|--Neo4jRelationshipModelService\nNeo4jRelationshipModelService : create()\n```\n\nSee source code for more details:\n\n- [🔗 Neo4jModelService](lib/service/neo4j.model.service.ts)\n- [🔗 Neo4jNodeModelService](lib/service/neo4j.node.model.service.ts)\n- [🔗 Neo4jRelationshipModelService](lib/service/neo4j.relationship.model.service.ts)\n\n#### Examples:\n\nLook at [🔗 E2e tests usage](spec/e2e) for more details\n\n```typescript\n/**\n * Cat Service example\n */\n\n@Injectable()\nexport class CatsService extends Neo4jNodeModelService\u003cCat\u003e {\n  constructor(protected readonly neo4jService: Neo4jService) {\n    super();\n  }\n\n  label = 'Cat';\n  logger = undefined;\n\n  fromNeo4j(model: Record\u003cstring, any\u003e): Cat {\n    return super.fromNeo4j({\n      ...model,\n      age: model.age.toNumber(),\n    });\n  }\n\n  toNeo4j(cat: Record\u003cstring, any\u003e): Record\u003cstring, any\u003e {\n    let result: Record\u003cstring, any\u003e = { ...cat };\n\n    if (!isNaN(result.age)) {\n      result.age = int(result.age);\n    }\n\n    return super.toNeo4j(result);\n  }\n\n  // Add a property named 'created' with timestamp on creation\n  protected timestamp = 'created';\n\n  findByName(\n    name: string,\n    options?: {\n      skip?: number;\n      limit?: number;\n      orderBy?: string;\n      descending?: boolean;\n    },\n  ) {\n    return super.findBy({ name }, options);\n  }\n\n  searchByName(\n    name: string,\n    options?: {\n      skip?: number;\n      limit?: number;\n    },\n  ) {\n    return super.searchBy('name', name.split(' '), options);\n  }\n}\n```\n\n```typescript\n/**\n * WORK_IN Controller example\n */\n\n@Controller('WORK_IN')\nexport class WorkInController {\n  constructor(\n    private readonly personService: PersonService,\n    private readonly workInService: WorkInService,\n    private readonly companyService: CompanyService,\n  ) {}\n\n  @Post('/:from/:to')\n  async workIn(\n    @Param('from') from: string,\n    @Param('to') to: string,\n    @Body() workInDto: WorkInDto,\n  ): Promise\u003c[PersonDto, WorkInDto, CompanyDto][]\u003e {\n    return this.workInService\n      .create(\n        workInDto,\n        { name: from },\n        { name: to },\n        this.personService,\n        this.companyService,\n      )\n      .run();\n  }\n\n  @Get()\n  async findAll(): Promise\u003c[PersonDto, WorkInDto, CompanyDto][]\u003e {\n    return this.workInService.findAll();\n  }\n}\n```\n\n## License\n\n[MIT licensed](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhogs%2Fnestjs-neo4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnhogs%2Fnestjs-neo4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnhogs%2Fnestjs-neo4j/lists"}