├── .nvmrc ├── src ├── ModelOps │ └── index.ts ├── Sessions │ ├── index.ts │ └── Sessions.ts ├── Queries │ ├── Where │ │ ├── index.ts │ │ ├── Where.spec.ts │ │ └── Where.ts │ ├── BindParam │ │ ├── index.ts │ │ └── BindParam.ts │ ├── Literal │ │ ├── index.ts │ │ └── Literal.ts │ ├── QueryRunner │ │ ├── index.ts │ │ ├── QueryRunner.spec.ts │ │ └── QueryRunner.ts │ ├── QueryBuilder │ │ └── index.ts │ └── index.ts ├── utils │ ├── string.ts │ ├── object.ts │ ├── StringSequence.ts │ └── temp.ts ├── test │ └── setupTests.ts ├── Errors │ ├── index.ts │ ├── NeogmaConnectivityError.ts │ ├── NeogmaError.ts │ ├── NeogmaNotFoundError.ts │ ├── NeogmaConstraintError.ts │ └── NeogmaInstanceValidationError.ts ├── index.ts ├── Neogma.spec.ts └── Neogma.ts ├── .env.example ├── tsconfig.spec.json ├── documentation ├── favicon.ico ├── .codedoc │ ├── package.json │ ├── theme.ts │ ├── content │ │ ├── theme.ts │ │ ├── header.tsx │ │ ├── footer.tsx │ │ └── index.tsx │ ├── build.ts │ ├── serve.ts │ ├── watch.ts │ ├── tsconfig.json │ └── config.ts ├── md │ ├── docs │ │ ├── QueryRunner │ │ │ ├── Running-Arbitrary-Queries.md │ │ │ ├── Overview.md │ │ │ ├── Creating-Nodes.md │ │ │ ├── Helpers.md │ │ │ ├── Deleting-Nodes.md │ │ │ ├── Creating-Relationships.md │ │ │ └── Updating-Nodes.md │ │ ├── QueryBuilder │ │ │ ├── With-Clause.md │ │ │ ├── Unwind-Clause.md │ │ │ ├── Set-Clause.md │ │ │ ├── Delete-Clause.md │ │ │ ├── Return-Clause.md │ │ │ ├── Limit-Skip-Clause.md │ │ │ ├── Remove-Clause.md │ │ │ ├── Clauses.md │ │ │ ├── Where-Clause.md │ │ │ ├── Order-By-Clause.md │ │ │ ├── Overview.md │ │ │ ├── Create-Clause.md │ │ │ ├── Match-Clause.md │ │ │ └── Helpers.md │ │ ├── Models │ │ │ ├── Overview.md │ │ │ ├── Deleting-Relationships.md │ │ │ ├── Deleting-Nodes.md │ │ │ ├── Hooks.md │ │ │ ├── Updating-Nodes-and-Relationships.md │ │ │ ├── Finding-Nodes-And-Relationships.md │ │ │ ├── Merging-Nodes-and-Relationships.md │ │ │ ├── Instances.md │ │ │ └── Creating-Nodes-and-Relationships.md │ │ ├── Temporary-Databases.md │ │ ├── Getting-Started.md │ │ ├── Bind-Parameters.md │ │ ├── Sessions-and-Transactions.md │ │ └── Where-Parameters.md │ ├── _toc.md │ └── index.md └── README.md ├── .prettierrc.json ├── .gitignore ├── tsconfig.json ├── docker-compose.yml ├── LICENSE ├── .github └── workflows │ ├── run-tests.yml │ └── publish.yml ├── eslint.config.js ├── package.json ├── jest.config.js └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.14.0 -------------------------------------------------------------------------------- /src/ModelOps/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ModelOps'; 2 | -------------------------------------------------------------------------------- /src/Sessions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Sessions'; 2 | -------------------------------------------------------------------------------- /src/Queries/Where/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Where'; 2 | -------------------------------------------------------------------------------- /src/Queries/BindParam/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BindParam'; 2 | -------------------------------------------------------------------------------- /src/Queries/Literal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Literal'; 2 | -------------------------------------------------------------------------------- /src/Queries/QueryRunner/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryRunner'; 2 | -------------------------------------------------------------------------------- /src/Queries/QueryBuilder/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QueryBuilder'; 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | NEO4J_URL=bolt://localhost:7687 2 | NEO4J_USERNAME=neo4j 3 | NEO4J_PASSWORD=password -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["node_modules"] 4 | } 5 | -------------------------------------------------------------------------------- /documentation/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themetalfleece/neogma/HEAD/documentation/favicon.ico -------------------------------------------------------------------------------- /documentation/.codedoc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@codedoc/core": "^0.3.2" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/string.ts: -------------------------------------------------------------------------------- 1 | export const trimWhitespace = (s: string, replaceWith = ' '): string => 2 | s.replace(/\s+/g, replaceWith)?.trim(); 3 | -------------------------------------------------------------------------------- /src/utils/object.ts: -------------------------------------------------------------------------------- 1 | export const isEmptyObject = (obj: Record): boolean => 2 | Object.entries(obj).length === 0 && obj.constructor === Object; 3 | -------------------------------------------------------------------------------- /src/Queries/Literal/Literal.ts: -------------------------------------------------------------------------------- 1 | export class Literal { 2 | constructor(private value: string) {} 3 | 4 | public getValue(): string { 5 | return this.value; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Queries/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BindParam'; 2 | export * from './QueryBuilder'; 3 | export * from './QueryRunner'; 4 | export * from './Where'; 5 | export * from './Literal'; 6 | -------------------------------------------------------------------------------- /src/test/setupTests.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | 3 | // Load .env file with quiet mode in CI to suppress console logs 4 | dotenv.config({ quiet: process.env.CI === 'true' }); 5 | -------------------------------------------------------------------------------- /src/Errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from './NeogmaConstraintError'; 2 | export * from './NeogmaError'; 3 | export * from './NeogmaInstanceValidationError'; 4 | export * from './NeogmaNotFoundError'; 5 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Errors'; 2 | export * from './Neogma'; 3 | export * from './ModelOps'; 4 | export * from './Queries'; 5 | export * from './Sessions'; 6 | 7 | export * as neo4jDriver from 'neo4j-driver'; 8 | -------------------------------------------------------------------------------- /documentation/.codedoc/theme.ts: -------------------------------------------------------------------------------- 1 | import { createTheme } from '@codedoc/core/transport'; 2 | 3 | export const theme = /*#__PURE__*/createTheme({ 4 | light: { 5 | primary: '#1eb2a6' 6 | }, 7 | dark: { 8 | primary: '#1eb2a6' 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node modules 2 | node_modules 3 | # environmental variables 4 | .env 5 | # built js directory 6 | dist 7 | # vscode config 8 | .vscode 9 | # test coverage 10 | coverage 11 | # generated docs 12 | documentation/docs 13 | documentation/index.html 14 | -------------------------------------------------------------------------------- /documentation/.codedoc/content/theme.ts: -------------------------------------------------------------------------------- 1 | import { funcTransport } from '@connectv/sdh/transport'; 2 | import { useTheme } from '@codedoc/core/transport'; 3 | 4 | import { theme } from '../theme'; 5 | 6 | export function installTheme() { useTheme(theme); } 7 | export const installTheme$ = /*#__PURE__*/funcTransport(installTheme); 8 | -------------------------------------------------------------------------------- /documentation/.codedoc/build.ts: -------------------------------------------------------------------------------- 1 | import { build } from '@codedoc/core'; 2 | 3 | import { config } from './config'; 4 | import { content } from './content'; 5 | import { installTheme$ } from './content/theme'; 6 | 7 | build(config, content, installTheme$, { 8 | resolve: { 9 | modules: ['.codedoc/node_modules'] 10 | }, 11 | resolveLoader: { 12 | modules: ['.codedoc/node_modules'] 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /src/Errors/NeogmaConnectivityError.ts: -------------------------------------------------------------------------------- 1 | import { NeogmaError } from './NeogmaError'; 2 | 3 | /** Error for when the connecting to neo4j is not possible */ 4 | export class NeogmaConnectivityError extends NeogmaError { 5 | constructor(data?: NeogmaConnectivityError['data']) { 6 | super('Error while connecting to neo4j', data); 7 | this.data = data || {}; 8 | 9 | Object.setPrototypeOf(this, NeogmaConnectivityError.prototype); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /documentation/.codedoc/serve.ts: -------------------------------------------------------------------------------- 1 | import { join } from 'path'; 2 | import { serve } from '@codedoc/core'; 3 | 4 | import { config } from './config'; 5 | import { content } from './content'; 6 | import { installTheme$ } from './content/theme'; 7 | 8 | const root = join(__dirname, '../'); 9 | 10 | serve(root, config, content, installTheme$, { 11 | resolve: { 12 | modules: ['.codedoc/node_modules'] 13 | }, 14 | resolveLoader: { 15 | modules: ['.codedoc/node_modules'] 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /src/Errors/NeogmaError.ts: -------------------------------------------------------------------------------- 1 | /** The base error which is thrown in neogma. All other errors entend this. */ 2 | export class NeogmaError extends Error { 3 | public message: string; 4 | public data: Record; 5 | 6 | constructor(message: NeogmaError['message'], data?: NeogmaError['data']) { 7 | super(message); 8 | this.message = message || 'General neogma error'; 9 | this.data = data || {}; 10 | 11 | Object.setPrototypeOf(this, NeogmaError.prototype); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "pretty": true, 6 | "resolveJsonModule": true, 7 | "declaration": true, 8 | "sourceMap": true, 9 | "esModuleInterop": true, 10 | "target": "es2017", 11 | "lib": ["es6", "es2015"], 12 | "outDir": "./dist", 13 | "baseUrl": "./src", 14 | "typeRoots": ["./node_modules/@types"], 15 | "strictNullChecks": true 16 | }, 17 | "include": ["src/**/*.ts"], 18 | "exclude": ["node_modules", "**/*.spec.ts"] 19 | } 20 | -------------------------------------------------------------------------------- /src/Errors/NeogmaNotFoundError.ts: -------------------------------------------------------------------------------- 1 | import { NeogmaError } from './NeogmaError'; 2 | 3 | /** General constraint error */ 4 | export class NeogmaNotFoundError extends NeogmaError { 5 | public message: NeogmaError['message']; 6 | public data: Record; 7 | 8 | constructor( 9 | message: NeogmaNotFoundError['message'], 10 | data?: NeogmaNotFoundError['data'], 11 | ) { 12 | super(message, data); 13 | this.message = message || 'neogma not found error'; 14 | this.data = data || {}; 15 | 16 | Object.setPrototypeOf(this, NeogmaNotFoundError.prototype); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /documentation/.codedoc/watch.ts: -------------------------------------------------------------------------------- 1 | import { exec, spawn } from 'child_process'; 2 | import { config } from './config'; 3 | 4 | const cmd = 'ts-node-dev'; 5 | const params = `--project .codedoc/tsconfig.json -T --watch ${config.src.base},.codedoc .codedoc/serve`; 6 | 7 | if (process.platform === 'win32') { 8 | const child = exec(cmd + ' ' + params); 9 | 10 | child.stdout?.pipe(process.stdout); 11 | child.stderr?.pipe(process.stderr); 12 | child.on('close', () => { }); 13 | } 14 | else { 15 | const child = spawn(cmd, [params], { stdio: 'inherit', shell: 'bash' }); 16 | child.on('close', () => { }); 17 | } -------------------------------------------------------------------------------- /src/Errors/NeogmaConstraintError.ts: -------------------------------------------------------------------------------- 1 | import { NeogmaError } from './NeogmaError'; 2 | 3 | /** General constraint error */ 4 | export class NeogmaConstraintError extends NeogmaError { 5 | public message: NeogmaError['message']; 6 | public data: { 7 | description?: any; 8 | actual?: any; 9 | expected?: any; 10 | }; 11 | 12 | constructor( 13 | message: NeogmaConstraintError['message'], 14 | data?: NeogmaConstraintError['data'], 15 | ) { 16 | super(message, data); 17 | this.message = message || 'neogma constraint error'; 18 | this.data = data || {}; 19 | 20 | Object.setPrototypeOf(this, NeogmaConstraintError.prototype); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /documentation/.codedoc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "noImplicitAny": true, 5 | "declaration": false, 6 | "strictNullChecks": true, 7 | "strictFunctionTypes": true, 8 | "noImplicitThis": true, 9 | "alwaysStrict": true, 10 | "sourceMap": true, 11 | "moduleResolution": "node", 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "experimentalDecorators": true, 15 | "emitDecoratorMetadata": true, 16 | "jsx": "react", 17 | "jsxFactory": "renderer.create", 18 | "lib": [ 19 | "es2017", 20 | "dom" 21 | ] 22 | }, 23 | "include": [ 24 | "./**/*" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /documentation/.codedoc/config.ts: -------------------------------------------------------------------------------- 1 | import { DefaultConfig, configuration } from '@codedoc/core'; 2 | 3 | import { theme } from './theme'; 4 | 5 | export const config = /*#__PURE__*/configuration({ 6 | theme, // --> add the theme. modify `./theme.ts` for chaning the theme. 7 | page: { 8 | title: { 9 | base: 'Neogma Documentation' // --> the base title of your doc pages 10 | }, 11 | favicon: '/favicon.ico' 12 | }, 13 | src: { 14 | base: './md' 15 | }, 16 | dest: { 17 | html: '.', 18 | namespace: '/neogma', 19 | }, 20 | misc: { 21 | github: { 22 | repo: 'neogma', 23 | user: 'themetalfleece', 24 | action: 'Star', 25 | } 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryRunner/Running-Arbitrary-Queries.md: -------------------------------------------------------------------------------- 1 | # Running Arbitrary Queries 2 | 3 | A `QueryRunner` instance can be used to run arbitrary/raw queries. 4 | 5 | ```js 6 | /* --> let 'queryRunner' be a QueryRunner instance */ 7 | const result = await queryRunner.run( 8 | /* --> arbitrary Cypher */ 9 | `MATCH (u:Users) WHERE u.id = $id RETURN u`, 10 | /* --> (optional) bind parameter for the statement */ 11 | { 12 | id: '1' 13 | }, 14 | /* --> (optional) an existing session or transaction to use */ 15 | null, 16 | ); 17 | 18 | /* --> the result is the QueryResult from the neo4j driver */ 19 | console.log(result.records.map((v) => v.get('u').properties)); 20 | ``` 21 | 22 | > :ToCPrevNext -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/With-Clause.md: -------------------------------------------------------------------------------- 1 | # With 2 | `QueryBuilderParameters['WithI']` 3 | 4 | ## With by using a literal string 5 | A literal string will be used as is. 6 | 7 | ```js 8 | const queryBuilder = new QueryBuilder() 9 | .with('a, b'); /* --> literal string to use */ 10 | 11 | console.log(queryBuilder.getStatement()); // WITH a, b 12 | console.log(queryBuilder.getBindParam().get()); // {} 13 | ``` 14 | 15 | ## With by using an array of strings 16 | An array of strings can be used, which will be joined with a comma. 17 | 18 | ```js 19 | const queryBuilder = new QueryBuilder() 20 | .with(['x', '{ y: x }']); 21 | 22 | console.log(queryBuilder.getStatement()); // WITH x, { y: x } 23 | console.log(queryBuilder.getBindParam().get()); // {} 24 | ``` 25 | -------------------------------------------------------------------------------- /src/Errors/NeogmaInstanceValidationError.ts: -------------------------------------------------------------------------------- 1 | import { NeogmaModel } from '../ModelOps'; 2 | import { NeogmaError } from './NeogmaError'; 3 | 4 | /** Error from validating an instance */ 5 | export class NeogmaInstanceValidationError extends NeogmaError { 6 | public message: NeogmaError['message']; 7 | public data: { 8 | model: NeogmaModel; 9 | errors: Revalidator.IErrrorProperty[]; 10 | }; 11 | 12 | constructor( 13 | message: NeogmaInstanceValidationError['message'], 14 | data: NeogmaInstanceValidationError['data'], 15 | ) { 16 | super(message, data); 17 | this.message = message || 'neogma validation error'; 18 | this.data = data; 19 | 20 | Object.setPrototypeOf(this, NeogmaInstanceValidationError.prototype); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /documentation/.codedoc/content/header.tsx: -------------------------------------------------------------------------------- 1 | import { CodedocConfig } from '@codedoc/core'; 2 | import { Header as _Header, GithubButton, Watermark } from '@codedoc/core/components'; 3 | 4 | 5 | export function Header(config: CodedocConfig, renderer: any) { 6 | return ( 7 | <_Header>{config.misc?.github ? 8 | 9 | 15 |

16 |
17 | : ''} 18 | 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /documentation/README.md: -------------------------------------------------------------------------------- 1 | ## This is the repository for the documentation of [neogma](https://github.com/themetalfleece/neogma) 2 | 3 | # [Documentation webpage index](https://themetalfleece.github.io/neogma) 4 | 5 | The docs are built with [codedoc](https://github.com/CONNECT-platform/codedoc). 6 | 7 | The source files are in the `md` directory. 8 | 9 | ## Building the docs 10 | 1) Install [codedoc](https://github.com/CONNECT-platform/codedoc), npm. 11 | 2) Navigate to this repo's directory, then to `documentation/.codedoc`. Run `npm i`. 12 | 3) To serve the docs for developing, navigate to this repo's directory and run `codedoc serve`. To access them, navigate to the url displayed in the terminal. 13 | 4) To build the static files to serve withe a web server, run `codedoc build`. The files will be build to the `docs` and `assets` directory. 14 | -------------------------------------------------------------------------------- /documentation/.codedoc/content/footer.tsx: -------------------------------------------------------------------------------- 1 | import { CodedocConfig } from '@codedoc/core'; 2 | import { Footer as _Footer, GitterToggle$, Watermark } from '@codedoc/core/components'; 3 | 4 | export function Footer(config: CodedocConfig, renderer: any) { 5 | let github$; 6 | if (config.misc?.github) 7 | github$ = GitHub; 9 | 10 | let community$; 11 | if (config.misc?.gitter) 12 | community$ = 13 | 14 | if (github$ && community$) return <_Footer>{github$}
{community$}; 15 | else if (github$) return <_Footer>{github$}; 16 | else if (community$) return <_Footer>{community$}; 17 | else return <_Footer>; 18 | } 19 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | neo4j: 3 | image: neo4j:5.26.1-enterprise 4 | container_name: neogma-neo4j 5 | ports: 6 | - "7474:7474" # HTTP 7 | - "7687:7687" # Bolt 8 | environment: 9 | - NEO4J_AUTH=neo4j/password 10 | - NEO4J_ACCEPT_LICENSE_AGREEMENT=yes 11 | - NEO4J_EDITION=ENTERPRISE 12 | - NEO4J_PLUGINS=["apoc"] 13 | - NEO4J_server_memory_heap_initial__size=512m 14 | - NEO4J_server_memory_heap_max__size=2G 15 | - NEO4J_server_memory_pagecache_size=512m 16 | volumes: 17 | - neo4j_data:/data 18 | - neo4j_logs:/logs 19 | healthcheck: 20 | test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider localhost:7474 || exit 1"] 21 | interval: 10s 22 | timeout: 5s 23 | retries: 5 24 | start_period: 30s 25 | 26 | volumes: 27 | neo4j_data: 28 | neo4j_logs: 29 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/Unwind-Clause.md: -------------------------------------------------------------------------------- 1 | # Unwind 2 | `QueryBuilderParameters['UnwindI']` 3 | 4 | ## Unwind by using a literal string 5 | A literal string will be used as is. 6 | 7 | ```js 8 | const queryBuilder = new QueryBuilder() 9 | .unwind('[1, 2, 3] as arr'); /* --> literal string to use */ 10 | 11 | console.log(queryBuilder.getStatement()); // UNWIND [1, 2, 3] as arr 12 | console.log(queryBuilder.getBindParam().get()); // {} 13 | ``` 14 | 15 | ## Unwind by using an object 16 | Unwind using an object with the value to unwind, and what to unwind as 17 | ```js 18 | const queryBuilder = new QueryBuilder().unwind({ 19 | /* --> unwind this value */ 20 | value: 'x', 21 | /* --> as this */ 22 | as: 'y' 23 | }); 24 | 25 | console.log(queryBuilder.getStatement()); // UNWIND x as y 26 | console.log(queryBuilder.getBindParam().get()); // {} 27 | ``` 28 | -------------------------------------------------------------------------------- /documentation/md/docs/Models/Overview.md: -------------------------------------------------------------------------------- 1 | # Models Overview 2 | 3 | Models provide lots of functions to automate creating, reading, updating, and deleting nodes and relationships. Every time a node is created or fetched from the database, an [Instance](./Instances) of this Model is created and provides access to its properties and other helper methods. 4 | 5 | To provide that functionality, a model definition needs the following configuration: 6 | * The label(s) that the nodes have. 7 | * All its potential relationships with other models (even itself). 8 | * A schema with the nodes' properties and validation for them. 9 | * (optional) Statics (for the Model) and methods (for the Instance). 10 | * (optional) A primary key field. The values of this field will be used as a unique identifier for the nodes, which will enable some methods to be used. 11 | 12 | Examples can be found next. 13 | 14 | > :ToCPrevNext -------------------------------------------------------------------------------- /src/Neogma.spec.ts: -------------------------------------------------------------------------------- 1 | import { Neogma } from './Neogma'; 2 | import { TEMPORARY_DB_PREFIX } from './utils/temp'; 3 | 4 | describe('Neogma', () => { 5 | let neogma: Neogma; 6 | 7 | beforeAll(async () => { 8 | neogma = await Neogma.fromTempDatabase({ 9 | url: process.env.NEO4J_URL ?? '', 10 | username: process.env.NEO4J_USERNAME ?? '', 11 | password: process.env.NEO4J_PASSWORD ?? '', 12 | }); 13 | 14 | await neogma.verifyConnectivity(); 15 | }, 30000); 16 | 17 | afterAll(async () => { 18 | await neogma.clearAllTempDatabases(); 19 | await neogma.driver.close(); 20 | }, 30000); 21 | 22 | it('should be defined', () => { 23 | expect(neogma).toBeDefined(); 24 | expect(neogma.database).toBeDefined(); 25 | expect(neogma.database).not.toBeNull(); 26 | }); 27 | 28 | it('should have created a temp db', async () => { 29 | expect(neogma.database?.indexOf(TEMPORARY_DB_PREFIX)).toBe(0); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/Set-Clause.md: -------------------------------------------------------------------------------- 1 | # Set 2 | `QueryBuilderParameters['SetI']` 3 | 4 | ## Set by using a literal string 5 | A literal string will be used as is. 6 | 7 | ```js 8 | const queryBuilder = new QueryBuilder() 9 | .set('a.id = 5'); /* --> literal string to use */ 10 | 11 | console.log(queryBuilder.getStatement()); // SET a.id = 5 12 | console.log(queryBuilder.getBindParam().get()); // {} 13 | ``` 14 | 15 | ## Set by using an object 16 | A SET statement can be generated using an object with an identifier and properties. 17 | 18 | ```js 19 | const queryBuilder = new QueryBuilder().set({ 20 | /* --> identifier whose properties will be set */ 21 | identifier: 'n', 22 | /* --> properties to set */ 23 | properties: { 24 | name: 'John', 25 | age: 28, 26 | }, 27 | }); 28 | 29 | console.log(queryBuilder.getStatement()); // SET n.name = $name AND n.age = $age 30 | console.log(queryBuilder.getBindParam().get()); // { name: 'John', age: 28 } 31 | ``` 32 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryRunner/Overview.md: -------------------------------------------------------------------------------- 1 | # The Query Runner 2 | 3 | The `QueryRunner` class can be used for arbitrary Cypher or Object-Graph mapping, without the need of defining Models. The parameters need to provide information about the labels etc. Bind parameters are used interally so there no need of escaping variables. 4 | 5 | It also provides some utilities to help with running your queries. 6 | 7 | ## Creating a QueryRunner Instance 8 | To run queries, a `QueryRunner` instance is needed. 9 | ```js 10 | const queryRunner = new QueryRunner({ 11 | /* --> a driver needs to be passed */ 12 | driver: neogma.driver, 13 | /* --> (optional) logs every query that this QueryRunner instance runs, using the given function */ 14 | logger: console.log 15 | /* --> (optional) Session config to be used when creating a session to run any query. If a custom session is passed to any method, this param will be ignored. */ 16 | sessionParams: { 17 | database: 'myDb' 18 | }, 19 | }); 20 | ``` 21 | 22 | > :ToCPrevNext -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jason Athanasoglou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /documentation/md/docs/Models/Deleting-Relationships.md: -------------------------------------------------------------------------------- 1 | # Deleting Relationshhips 2 | 3 | ## Deleting Relationshhips via the Model static 4 | 5 | Using the `deleteRelationships` static of a Model and providing a Where parameter, relationships of the Model can be deleted 6 | 7 | ```js 8 | await Users.deleteRelationships({ 9 | /* --> the Relationshhips to be deleted will be matched using this param */ 10 | where: { 11 | /* --> (optional) the relationship(s) to be deleted need to be from a User with the name 'John' AND the id '1' */ 12 | source: { 13 | name: 'John', 14 | id: 1, 15 | }, 16 | /* --> (optional) the relationship(s) to be deleted need to be to an Order with the id '2' */ 17 | target: { 18 | id: 1, 19 | }, 20 | /* --> (optional) the relationship(s) to be deleted need to be match the following properties */ 21 | relationship: { 22 | rating: 5, 23 | status: 'completed', 24 | }, 25 | }, 26 | /* --> (optional) an existing session or transaction to use */ 27 | session: null, 28 | }); 29 | ``` 30 | 31 | > :ToCPrevNext -------------------------------------------------------------------------------- /documentation/md/docs/QueryRunner/Creating-Nodes.md: -------------------------------------------------------------------------------- 1 | # Creating Nodes 2 | 3 | A `QueryRunner` instance can be used for creating nodes from Objects. The node properties and label are needed. 4 | 5 | ```js 6 | /* --> let 'queryRunner' be a QueryRunner instance */ 7 | const result = await queryRunner.create({ 8 | /* --> label(s) of the created nodes. Multiple labels like 'User:Person' can also be used */ 9 | label: 'User', 10 | /* --> data (properties) for the nodes. Here, 2 nodes will be created */ 11 | data: [ 12 | { 13 | phoneNumber: '1234567890', 14 | codes: [0, 3, 8], 15 | }, 16 | { 17 | age: 38, 18 | } 19 | ], 20 | /* --> (optional) the identifier of the nodes for the query. Is needed for parsing the results. Default is the value of 'QueryRunner.identifiers.default' */ 21 | identifier: 'u', 22 | /* --> (optional) an existing session or transaction to use */ 23 | session: null, 24 | }); 25 | 26 | /* --> the result is the QueryResult from the neo4j driver */ 27 | console.log(result.records.map((v) => v.get('u').properties)); 28 | ``` 29 | 30 | > :ToCPrevNext -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | runTests: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version-file: '.nvmrc' 23 | cache: 'yarn' 24 | 25 | - name: Start Neo4j with Docker Compose 26 | run: docker compose up -d 27 | 28 | - name: Install dependencies 29 | run: yarn install --frozen-lockfile 30 | 31 | - name: Wait for Neo4j 32 | uses: ifaxity/wait-on-action@v1.1.0 33 | with: 34 | resource: http://localhost:7474 35 | timeout: 60000 36 | 37 | - name: Run tests 38 | env: 39 | CI: true 40 | NEO4J_URL: bolt://localhost:7687 41 | NEO4J_USERNAME: neo4j 42 | NEO4J_PASSWORD: password 43 | run: yarn test 44 | 45 | - name: Stop Neo4j 46 | if: always() 47 | run: docker compose down -v 48 | -------------------------------------------------------------------------------- /documentation/md/docs/Models/Deleting-Nodes.md: -------------------------------------------------------------------------------- 1 | # Deleting Nodes 2 | 3 | ## Deleting Nodes via the Model static 4 | 5 | Using the `delete` static of a Model and providing a Where parameter, nodes of the Model can be deleted 6 | 7 | ```js 8 | await Users.delete({ 9 | /* --> the Nodes to be deleted will be matched using this param */ 10 | where: { 11 | /* --> the node(s) to be deleted need to have the name 'John' AND the id '1' */ 12 | name: 'John', 13 | id: '1' 14 | }, 15 | /* --> (optional) adds the DETACH keyword to the delete statement, also deleting the relationships of the node(s) */ 16 | detach: true, 17 | /* --> (optional) an existing session or transaction to use */ 18 | session: null, 19 | }); 20 | ``` 21 | 22 | ## Deleting Nodes via the Instance method 23 | 24 | Using the `delete` method of an Instance, the node which corresponds to the Instance will be deleted. 25 | 26 | ```js 27 | /* --> let 'user' be a Users Instance. This node will be deleted */ 28 | await user.delete({ 29 | /* --> (optional) adds the DETACH keyword to the delete statement, also deleting the relationships of the node */ 30 | detach: true, 31 | /* --> (optional) an existing session or transaction to use */ 32 | session: null, 33 | }); 34 | ``` 35 | 36 | > :ToCPrevNext -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/Delete-Clause.md: -------------------------------------------------------------------------------- 1 | # Delete 2 | `QueryBuilderParameters['DeleteI']` 3 | 4 | ## Delete by using a literal string 5 | A literal string will be used as is. 6 | 7 | ```js 8 | const queryBuilder = new QueryBuilder() 9 | .delete('a, b'); /* --> literal string to use */ 10 | 11 | console.log(queryBuilder.getStatement()); // DELETE a, b 12 | console.log(queryBuilder.getBindParam().get()); // {} 13 | ``` 14 | 15 | ## Delete by using a literal object 16 | This has the benefit of being able to use `detach` delete. 17 | 18 | ```js 19 | const queryBuilder = new QueryBuilder().delete({ 20 | /* --> literal string to use */ 21 | literal: 'a, b', 22 | /* --> (optional) whether this delete will be "detach" */ 23 | detach: true, 24 | }); 25 | 26 | console.log(queryBuilder.getStatement()); // DETACH DELETE a, b 27 | console.log(queryBuilder.getBindParam().get()); // {} 28 | ``` 29 | 30 | ## Delete by using an array of identifiers 31 | ```js 32 | const queryBuilder = new QueryBuilder().delete({ 33 | /* --> the identifiers to be deleted */ 34 | identifiers: ['a', 'b'], 35 | /* --> (optional) whether this delete will be "detach" */ 36 | detach: false, 37 | }); 38 | 39 | console.log(queryBuilder.getStatement()); // DELETE a, b 40 | console.log(queryBuilder.getBindParam().get()); // {} 41 | ``` 42 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/Return-Clause.md: -------------------------------------------------------------------------------- 1 | # Return 2 | 3 | ## Return by using a literal string 4 | A literal string will be used as is. 5 | 6 | ```js 7 | const queryBuilder = new QueryBuilder() 8 | .return('a, b.p1'); /* --> literal string to use */ 9 | 10 | console.log(queryBuilder.getStatement()); // RETURN a, b.p1 11 | console.log(queryBuilder.getBindParam().get()); // {} 12 | ``` 13 | 14 | ## Return by using an array of literal strings 15 | The literal strings will be joined with a comma. 16 | 17 | ```js 18 | const queryBuilder = new QueryBuilder() 19 | .return(['a', 'b.p1']); /* --> literal strings to use */ 20 | 21 | console.log(queryBuilder.getStatement()); // RETURN a, b.p1 22 | console.log(queryBuilder.getBindParam().get()); // {} 23 | ``` 24 | 25 | ## Order by, by using an object array 26 | An array of objects with an identifier/name, and an optional property. 27 | 28 | ```js 29 | const queryBuilder = new QueryBuilder().return([ 30 | { 31 | /* --> identifier/name to return */ 32 | identifier: 'a', 33 | /* --> (optional) the property of the identifier to return */ 34 | property: 'name', 35 | } 36 | { 37 | identifier: 'b' 38 | } 39 | ]); 40 | 41 | console.log(queryBuilder.getStatement()); // RETURN a.name, b 42 | console.log(queryBuilder.getBindParam().get()); // {} 43 | ``` 44 | -------------------------------------------------------------------------------- /documentation/md/docs/QueryBuilder/Limit-Skip-Clause.md: -------------------------------------------------------------------------------- 1 | # Limit 2 | 3 | ## Limit by using a literal string 4 | A literal string will be used as is. 5 | 6 | ```js 7 | const queryBuilder = new QueryBuilder() 8 | .limit('toInteger(3 * rand()) + 1'); /* --> literal string to use */ 9 | 10 | console.log(queryBuilder.getStatement()); // LIMIT toInteger(3 * rand()) + 1 11 | console.log(queryBuilder.getBindParam().get()); // {} 12 | ``` 13 | 14 | ## Limit by using a number 15 | That way, a Bind Parameter is used 16 | 17 | ```js 18 | const queryBuilder = new QueryBuilder().limit(5); 19 | 20 | console.log(queryBuilder.getStatement()); // LIMIT $limit 21 | console.log(queryBuilder.getBindParam().get()); // { limit: 5 } 22 | ``` 23 | 24 | # Skip 25 | 26 | ## Skip by using a literal string 27 | A literal string will be used as is. 28 | 29 | ```js 30 | const queryBuilder = new QueryBuilder() 31 | .skip('toInteger(3 * rand()) + 1'); /* --> literal string to use */ 32 | 33 | console.log(queryBuilder.getStatement()); // SKIP toInteger(3 * rand()) + 1 34 | console.log(queryBuilder.getBindParam().get()); // {} 35 | ``` 36 | 37 | ## Skip by using a number 38 | That way, a Bind Parameter is used 39 | 40 | ```js 41 | const queryBuilder = new QueryBuilder().skip(5); 42 | 43 | console.log(queryBuilder.getStatement()); // SKIP $skip 44 | console.log(queryBuilder.getBindParam().get()); // { skip: 5 } 45 | ``` 46 | -------------------------------------------------------------------------------- /documentation/.codedoc/content/index.tsx: -------------------------------------------------------------------------------- 1 | import { RendererLike } from '@connectv/html'; 2 | import { File } from 'rxline/fs'; 3 | import { Page, Meta, ContentNav, Fonts, ToC, GithubSearch$ } from '@codedoc/core/components'; 4 | 5 | import { config } from '../config'; 6 | import { Header } from './header'; 7 | import { Footer } from './footer'; 8 | 9 | 10 | export function content(_content: HTMLElement, toc: HTMLElement, renderer: RendererLike, file: File) { 11 | return ( 12 | } 15 | fonts={} 16 | 17 | scripts={config.page.scripts} 18 | stylesheets={config.page.stylesheets} 19 | 20 | header={
} 21 | footer={