├── resources ├── final.png ├── light │ ├── document.svg │ ├── edit.svg │ ├── folder.svg │ ├── boolean.svg │ ├── dependency.svg │ ├── refresh.svg │ ├── number.svg │ └── string.svg └── dark │ ├── edit.svg │ ├── document.svg │ ├── folder.svg │ ├── boolean.svg │ ├── dependency.svg │ ├── refresh.svg │ ├── number.svg │ └── string.svg ├── .gitignore ├── DOCUMENTATION ├── Trinity-Logo.png ├── gifs │ └── basicDemo.gif └── docs │ ├── featureRequest.md │ ├── bugReport.md │ └── contributing.md ├── .vscodeignore ├── .trinity.json ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── launch.json ├── CHANGELOG.md ├── src ├── server │ └── neo4j │ │ ├── sampleOutput │ │ ├── labelsAndPropertySummary.json │ │ ├── relationshipSummary.json │ │ └── movie.cypher │ │ ├── types │ │ ├── query-runner.d.ts │ │ ├── transaction.d.ts │ │ ├── result-rx.d.ts │ │ ├── transaction-rx.d.ts │ │ ├── spatial-types.d.ts │ │ ├── error.d.ts │ │ ├── result.d.ts │ │ ├── record.d.ts │ │ ├── session-rx.d.ts │ │ ├── session.d.ts │ │ ├── graph-types.d.ts │ │ ├── result-summary.d.ts │ │ ├── driver.d.ts │ │ ├── temporal-types.d.ts │ │ ├── integer.d.ts │ │ └── index.d.ts │ │ └── graphdb-outline-ts.ts ├── test │ ├── runTest.ts │ └── suite │ │ ├── index.ts │ │ └── extension.test.ts ├── extension.ts └── modules │ ├── queryRunner.ts │ ├── parseExtract.ts │ ├── readConfig.ts │ └── OutlineProvider.ts ├── .eslintrc.json ├── tsconfig.json ├── LICENSE ├── webpack.config.js ├── vsc-extension-quickstart.md ├── package.json └── README.md /resources/final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Trinity/HEAD/resources/final.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .vscode-test/ 4 | *.vsix 5 | .DS_Store 6 | Trinity.code-workspace 7 | -------------------------------------------------------------------------------- /DOCUMENTATION/Trinity-Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Trinity/HEAD/DOCUMENTATION/Trinity-Logo.png -------------------------------------------------------------------------------- /DOCUMENTATION/gifs/basicDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/Trinity/HEAD/DOCUMENTATION/gifs/basicDemo.gif -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | -------------------------------------------------------------------------------- /.trinity.json: -------------------------------------------------------------------------------- 1 | { 2 | "dbAddress": "bolt://localhost", 3 | "username": "neo4j", 4 | "password": "test", 5 | "readOnly": true, 6 | "clearChannelOnSave": false, 7 | "cearChannelOnSave": false 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to the "trinity" extension will be documented in this file. 4 | 5 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 6 | 7 | ## [Unreleased] 8 | 9 | - Initial release -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/server/neo4j/sampleOutput/labelsAndPropertySummary.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "Database", 4 | "properties": ["name"] 5 | }, 6 | { 7 | "label": "Message", 8 | "properties": ["name"] 9 | }, 10 | { 11 | "label": "Movie", 12 | "properties": ["title", "tagline", "released"] 13 | }, 14 | { 15 | "label": "PERSON", 16 | "properties": ["name"] 17 | }, 18 | { 19 | "label": "Person", 20 | "properties": ["born", "name"] 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 10 | "typescript.tsc.autoDetect": "off" 11 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/class-name-casing": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /resources/light/document.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | }, 17 | "exclude": [ 18 | "node_modules", 19 | ".vscode-test" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /resources/dark/document.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /resources/light/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DOCUMENTATION/docs/featureRequest.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 12 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 13 | 14 | 15 | **Describe the solution you'd like** 16 | 17 | A clear and concise description of what you want to happen. 18 | 19 | 20 | **Describe alternatives you've considered** 21 | 22 | A clear and concise description of any alternative solutions or features you've considered. 23 | 24 | 25 | **Additional context** 26 | 27 | Add any other context or screenshots about the feature request here. 28 | 29 | -------------------------------------------------------------------------------- /resources/dark/folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/boolean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/dependency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/boolean.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/dependency.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DOCUMENTATION/docs/bugReport.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Version [e.g. 22] 29 | - VS Code Version 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /src/server/neo4j/sampleOutput/relationshipSummary.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "originNode": ["Person"], 4 | "relationship": "ACTED_IN", 5 | "dependentNode": ["Movie"] 6 | }, 7 | { 8 | "originNode": ["Person"], 9 | "relationship": "DIRECTED", 10 | "dependentNode": ["Movie"] 11 | }, 12 | { 13 | "originNode": ["Person"], 14 | "relationship": "PRODUCED", 15 | "dependentNode": ["Movie"] 16 | }, 17 | { 18 | "originNode": ["Person"], 19 | "relationship": "WROTE", 20 | "dependentNode": ["Movie"] 21 | }, 22 | { 23 | "originNode": ["Person"], 24 | "relationship": "FOLLOWS", 25 | "dependentNode": ["Person"] 26 | }, 27 | { 28 | "originNode": ["Person"], 29 | "relationship": "REVIEWED", 30 | "dependentNode": ["Movie"] 31 | }, 32 | { 33 | "originNode": ["Database"], 34 | "relationship": "SAYS", 35 | "dependentNode": ["Message"] 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | }); 10 | mocha.useColors(true); 11 | 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | 14 | return new Promise((c, e) => { 15 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 16 | if (err) { 17 | return e(err); 18 | } 19 | 20 | // Add files to the test suite 21 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 22 | 23 | try { 24 | // Run the mocha test 25 | mocha.run(failures => { 26 | if (failures > 0) { 27 | e(new Error(`${failures} tests failed.`)); 28 | } else { 29 | c(); 30 | } 31 | }); 32 | } catch (err) { 33 | console.error(err); 34 | e(err); 35 | } 36 | }); 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /resources/dark/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/server/neo4j/types/query-runner.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Result from "./result"; 21 | 22 | declare type Parameters = { [key: string]: any }; 23 | 24 | declare interface QueryRunner { 25 | run(query: string, parameters?: Parameters): Result; 26 | } 27 | 28 | export { Parameters }; 29 | 30 | export default QueryRunner; 31 | -------------------------------------------------------------------------------- /src/server/neo4j/types/transaction.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Result from "./result"; 21 | import QueryRunner from "./query-runner"; 22 | 23 | declare interface Transaction extends QueryRunner { 24 | commit(): Promise; 25 | 26 | rollback(): Promise; 27 | 28 | isOpen(): boolean; 29 | } 30 | 31 | export default Transaction; 32 | -------------------------------------------------------------------------------- /src/server/neo4j/types/result-rx.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | import { Observable } from "rxjs"; 20 | import ResultSummary from "./result-summary"; 21 | import Record from "./record"; 22 | 23 | declare interface RxResult { 24 | keys(): Observable; 25 | 26 | records(): Observable; 27 | 28 | summary(): Observable; 29 | } 30 | 31 | export default RxResult; 32 | -------------------------------------------------------------------------------- /src/server/neo4j/types/transaction-rx.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | import { Observable } from "rxjs"; 20 | import { Parameters } from "./query-runner"; 21 | import RxResult from "./result-rx"; 22 | 23 | declare interface RxTransaction { 24 | run(query: string, parameters?: Parameters): RxResult; 25 | 26 | commit(): Observable; 27 | 28 | rollback(): Observable; 29 | } 30 | 31 | export default RxTransaction; 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 OSLabs Beta 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 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "${defaultBuildTask}" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "${defaultBuildTask}" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /src/server/neo4j/types/spatial-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { NumberOrInteger } from "./graph-types"; 21 | import Integer from "./integer"; 22 | 23 | declare class Point { 24 | readonly srid: T; 25 | readonly x: number; 26 | readonly y: number; 27 | readonly z?: number; 28 | 29 | constructor(srid: T, x: number, y: number, z?: number); 30 | } 31 | 32 | declare function isPoint(obj: object): boolean; 33 | 34 | export { Point, isPoint }; 35 | -------------------------------------------------------------------------------- /src/server/neo4j/types/error.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | declare const SERVICE_UNAVAILABLE: string; 21 | declare const SESSION_EXPIRED: string; 22 | declare const PROTOCOL_ERROR: string; 23 | 24 | declare function newError(message: any, code?: string): Neo4jError; 25 | 26 | declare class Neo4jError extends Error { 27 | code: string; 28 | message: string; 29 | 30 | constructor(message: any, code?: string); 31 | } 32 | 33 | export { 34 | newError, 35 | Neo4jError, 36 | SERVICE_UNAVAILABLE, 37 | SESSION_EXPIRED, 38 | PROTOCOL_ERROR 39 | }; 40 | -------------------------------------------------------------------------------- /src/server/neo4j/types/result.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import ResultSummary from "./result-summary"; 21 | import Record from "./record"; 22 | 23 | declare type QueryResult = { 24 | records: Record[]; 25 | summary: ResultSummary; 26 | }; 27 | 28 | declare type ResultObserver = { 29 | onKeys?(keys: string[]): void; 30 | onNext?(record: Record): void; 31 | onCompleted?(summary: ResultSummary): void; 32 | onError?(error: Error): void; 33 | }; 34 | 35 | declare interface Result extends Promise { 36 | subscribe(observer: ResultObserver): void; 37 | } 38 | 39 | export { QueryResult, ResultObserver }; 40 | export default Result; 41 | -------------------------------------------------------------------------------- /src/server/neo4j/types/record.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | declare type Visitor = (value: any, key: string, record: Record) => void; 21 | 22 | declare type MapVisitor = (value: any, key: string, record: Record) => T; 23 | 24 | declare class Record { 25 | keys: string[]; 26 | length: number; 27 | _fields: any[]; 28 | 29 | constructor( 30 | keys: string[], 31 | fields: any[], 32 | fieldLookup?: { [index: string]: string } 33 | ); 34 | 35 | forEach(visitor: Visitor): void; 36 | 37 | map(visitor: MapVisitor): T[]; 38 | 39 | toObject(): object; 40 | 41 | get(key: string | number): any; 42 | 43 | has(key: string | number): boolean; 44 | } 45 | 46 | export default Record; 47 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | //@ts-check 2 | 3 | 'use strict'; 4 | 5 | const path = require('path'); 6 | 7 | /** 8 | * @type {import('webpack').Configuration} 9 | * 10 | * */ 11 | 12 | const config = { 13 | target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ 14 | 15 | entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ 16 | output: { 17 | // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ 18 | path: path.resolve(__dirname, 'dist'), 19 | filename: 'extension.js', 20 | libraryTarget: 'commonjs2', 21 | devtoolModuleFilenameTemplate: '../[resource-path]' 22 | }, 23 | devtool: 'source-map', 24 | externals: { 25 | vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ 26 | }, 27 | resolve: { 28 | // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader 29 | extensions: ['.ts', '.js'] 30 | }, 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.ts$/, 35 | exclude: /node_modules/, 36 | use: [ 37 | { 38 | loader: 'ts-loader' 39 | } 40 | ] 41 | } 42 | ] 43 | } 44 | }; 45 | module.exports = config; -------------------------------------------------------------------------------- /src/server/neo4j/types/session-rx.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | import RxResult from "./result-rx"; 20 | import RxTransaction from "./transaction-rx"; 21 | import { TransactionConfig } from "./session"; 22 | import { Parameters } from "./query-runner"; 23 | import { Observable } from "rxjs"; 24 | 25 | declare type RxTransactionWork = (tx: RxTransaction) => Observable; 26 | 27 | declare interface RxSession { 28 | run( 29 | query: string, 30 | parameters?: Parameters, 31 | config?: TransactionConfig 32 | ): RxResult; 33 | 34 | beginTransaction(config?: TransactionConfig): Observable; 35 | 36 | lastBookmark(): string | null; 37 | 38 | readTransaction( 39 | work: RxTransactionWork, 40 | config?: TransactionConfig 41 | ): Observable; 42 | 43 | writeTransaction( 44 | work: RxTransactionWork, 45 | config?: TransactionConfig 46 | ): Observable; 47 | 48 | close(): Observable; 49 | } 50 | 51 | export default RxSession; 52 | -------------------------------------------------------------------------------- /src/server/neo4j/types/session.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Transaction from "./transaction"; 21 | import QueryRunner, { Parameters } from "./query-runner"; 22 | import Result from "./result"; 23 | import { NumberOrInteger } from "./graph-types"; 24 | 25 | declare type TransactionWork = (tx: Transaction) => T | Promise; 26 | 27 | declare interface TransactionConfig { 28 | timeout?: NumberOrInteger; 29 | metadata?: object; 30 | } 31 | 32 | declare interface Session extends QueryRunner { 33 | run( 34 | query: string, 35 | parameters?: Parameters, 36 | config?: TransactionConfig 37 | ): Result; 38 | 39 | beginTransaction(config?: TransactionConfig): Transaction; 40 | 41 | lastBookmark(): string | null; 42 | 43 | readTransaction( 44 | work: TransactionWork, 45 | config?: TransactionConfig 46 | ): Promise; 47 | 48 | writeTransaction( 49 | work: TransactionWork, 50 | config?: TransactionConfig 51 | ): Promise; 52 | 53 | close(): Promise; 54 | } 55 | 56 | export { TransactionConfig }; 57 | 58 | export default Session; 59 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { QueryRunner } from "./modules/queryRunner"; 3 | const { OutlineProvider }=require("./modules/OutlineProvider"); 4 | import { TrinityConfig } from "./modules/readConfig"; 5 | 6 | // this required method is called when your extension is activated 7 | export function activate(context: vscode.ExtensionContext) { 8 | vscode.commands.registerCommand("extension.runTrinity", () => { 9 | vscode.window.showInformationMessage( 10 | "Trinity is now running! Add your workspace at the search bar at top of window." 11 | ); 12 | }); 13 | 14 | // Load configuration and event watcher 15 | const trinityConfig: TrinityConfig=new TrinityConfig(); 16 | // Trigger event watcher 17 | trinityConfig.getActiveWorkspace().then(() => { 18 | // Loading outline provider with active settings 19 | const OP=new OutlineProvider(context, trinityConfig); 20 | // displaying view 21 | OP.show(); 22 | vscode.window.registerTreeDataProvider("trinityOutline", OP); 23 | vscode.commands.registerCommand("trinityOutline.refresh", () => 24 | OP.createGraphStructure() 25 | ); 26 | vscode.commands.registerCommand("trinityOutline.show", () => { 27 | OP.show(); 28 | }); 29 | // Create a new setup Extension to handle live querying and 30 | // create a Trinity Channel 31 | const queryRunner=new QueryRunner(trinityConfig); 32 | // functionality executed every time the active document is saved 33 | vscode.workspace.onDidSaveTextDocument(event => 34 | queryRunner.handleSave(event) 35 | ); 36 | 37 | // deactivate functionality 38 | vscode.commands.registerCommand("extension.deactivateTrinity", () => { 39 | // this command will restart window automatically and Trinity extension will not be running 40 | vscode.commands.executeCommand("workbench.action.reloadWindow"); 41 | }); 42 | }); 43 | } 44 | 45 | export function deactivate() { } 46 | -------------------------------------------------------------------------------- /DOCUMENTATION/docs/contributing.md: -------------------------------------------------------------------------------- 1 | ## Contributing to Trinity 2 | 3 | We would appreciate any input on making Trinity better. To contribute for any bugs please follow the instructions below. 4 | 5 | ### Reporting a bug 6 | 7 | Discussing the current state of the code 8 | Submitting a fix 9 | Proposing new features 10 | We Develop with Github 11 | We use Github to host code, to track issues and feature requests, as well as accept pull requests. 12 | 13 | All Code Changes Happen Through Pull Requests 14 | Pull requests are the best way to propose changes to Trinity. We actively welcome your pull requests: 15 | 16 | Fork the repo and create your branch from dev. 17 | If you've added code that should be tested, add tests. 18 | If you've changed APIs, update the documentation. 19 | Ensure the test suite passes. 20 | Make sure your code lints. 21 | Issue that pull request! 22 | Any contributions you make will be under the MIT Software License 23 | In short, when you submit code changes, your submissions are understood to be under the same that covers the project. Feel free to contact the maintainers if that's a concern. 24 | 25 | ### Report bugs using Github's issues 26 | 27 | We use GitHub issues to track public bugs. Report a bug by opening a new issue; it's that easy! 28 | 29 | Write bug reports with detail, background, and sample code 30 | Great Bug Reports tend to have: 31 | 32 | ### A quick summary and/or background 33 | 34 | Steps to reproduce 35 | Be specific! 36 | Give sample code if you can. Include sample code that anyone can run to reproduce what you are experiencing 37 | What you expected would happen 38 | What actually happens 39 | Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) 40 | People love thorough bug reports. I'm not even kidding. 41 | 42 | ### Use a Consistent Coding Style (Airbnb) 43 | 44 | We have our included our eslint setup in this repo to make this as painless as possible. Please also install the VS Code [Eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension. 45 | 46 | #### License 47 | 48 | By contributing, you agree that your contributions will be licensed under its MIT License. 49 | 50 | #### References 51 | 52 | This document was adapted from the open-source contribution guidelines for Facebook's Draft 53 | -------------------------------------------------------------------------------- /vsc-extension-quickstart.md: -------------------------------------------------------------------------------- 1 | # Welcome to your VS Code Extension 2 | 3 | ## What's in the folder 4 | 5 | * This folder contains all of the files necessary for your extension. 6 | * `package.json` - this is the manifest file in which you declare your extension and command. 7 | * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. 8 | * `src/extension.ts` - this is the main file where you will provide the implementation of your command. 9 | * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. 10 | * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. 11 | 12 | ## Get up and running straight away 13 | 14 | * Press `F5` to open a new window with your extension loaded. 15 | * Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. 16 | * Set breakpoints in your code inside `src/extension.ts` to debug your extension. 17 | * Find output from your extension in the debug console. 18 | 19 | ## Make changes 20 | 21 | * You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. 22 | * You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. 23 | 24 | 25 | ## Explore the API 26 | 27 | * You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. 28 | 29 | ## Run tests 30 | 31 | * Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. 32 | * Press `F5` to run the tests in a new window with your extension loaded. 33 | * See the output of the test result in the debug console. 34 | * Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. 35 | * The provided test runner will only consider files matching the name pattern `**.test.ts`. 36 | * You can create folders inside the `test` folder to structure your tests any way you want. 37 | 38 | ## Go further 39 | 40 | * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). 41 | * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. 42 | * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration). 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "trinity", 3 | "displayName": "Trinity", 4 | "description": "VSCode extension for Cypher and Neo4j", 5 | "version": "0.2.0", 6 | "publisher": "Trinity", 7 | "icon": "resources/final.png", 8 | "engines": { 9 | "vscode": "^1.42.0" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/oslabs-beta/Trinity" 14 | }, 15 | "categories": [ 16 | "Extension Packs", 17 | "Language Packs", 18 | "Other" 19 | ], 20 | "activationEvents": [ 21 | "onCommand:extension.runTrinity", 22 | "onCommand:extension.deactivateTrinity" 23 | ], 24 | "main": "./out/extension.js", 25 | "contributes": { 26 | "commands": [ 27 | { 28 | "command": "extension.runTrinity", 29 | "title": "Trinity: Run Trinity" 30 | }, 31 | { 32 | "command": "extension.deactivateTrinity", 33 | "title": "Trinity: Deactivate Trinity" 34 | }, 35 | { 36 | "command": "trinityOutline.refresh", 37 | "title": "Refresh", 38 | "icon": { 39 | "light": "resources/light/refresh.svg", 40 | "dark": "resources/dark/refresh.svg" 41 | } 42 | } 43 | ], 44 | "views": { 45 | "explorer": [ 46 | { 47 | "id": "trinityOutline", 48 | "name": "Trinity Outline", 49 | "when": "trinityOutlineEnabled" 50 | } 51 | ] 52 | }, 53 | "menus": { 54 | "view/title": [ 55 | { 56 | "command": "trinityOutline.refresh", 57 | "when": "view == trinityOutline", 58 | "group": "navigation" 59 | } 60 | ] 61 | } 62 | }, 63 | "scripts": { 64 | "vscode:prepublish": "webpack --mode production", 65 | "compile": "tsc -p ./", 66 | "lint": "eslint src --ext ts", 67 | "watch": "tsc -watch -p ./", 68 | "pretest": "npm run compile && npm run lint", 69 | "test": "node ./out/test/runTest.js", 70 | "webpack": "webpack --mode development", 71 | "webpack-dev": "webpack --mode development -watch", 72 | "test-compile": "tsc -p ./" 73 | }, 74 | "devDependencies": { 75 | "@types/find": "^0.2.1", 76 | "@types/glob": "^7.1.1", 77 | "@types/mocha": "^7.0.1", 78 | "@types/node": "^12.12.28", 79 | "@types/vscode": "^1.42.0", 80 | "@typescript-eslint/eslint-plugin": "^2.18.0", 81 | "@typescript-eslint/parser": "^2.18.0", 82 | "eslint": "^6.8.0", 83 | "glob": "^7.1.6", 84 | "mocha": "^7.0.1", 85 | "ts-loader": "^6.2.1", 86 | "typescript": "^3.7.5", 87 | "vscode-test": "^1.3.0", 88 | "webpack": "^4.41.6", 89 | "webpack-cli": "^3.3.11" 90 | }, 91 | "dependencies": { 92 | "find": "^0.3.0", 93 | "neo4j-driver": "^4.0.1", 94 | "parcel-bundler": "^1.12.4", 95 | "parcel-plugin-typescript": "^1.0.0", 96 | "walk": "^2.3.14" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/server/neo4j/types/graph-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Integer from "./integer"; 21 | 22 | declare type StandardDate = Date; 23 | declare type NumberOrInteger = number | Integer; 24 | 25 | declare class Node { 26 | identity: T; 27 | labels: string[]; 28 | properties: object; 29 | 30 | constructor(identity: T, labels: string[], properties: object); 31 | 32 | toString(): string; 33 | } 34 | 35 | declare class Relationship { 36 | identity: T; 37 | start: T; 38 | end: T; 39 | type: string; 40 | properties: object; 41 | 42 | constructor(identity: T, start: T, end: T, type: string, properties: object); 43 | 44 | toString(): string; 45 | } 46 | 47 | declare class UnboundRelationship { 48 | identity: T; 49 | type: string; 50 | properties: object; 51 | 52 | constructor(identity: T, type: string, properties: object); 53 | 54 | bind(start: T, end: T): Relationship; 55 | 56 | toString(): string; 57 | } 58 | 59 | declare class PathSegment { 60 | start: Node; 61 | relationship: Relationship; 62 | end: Node; 63 | 64 | constructor(start: Node, rel: Relationship, end: Node); 65 | } 66 | 67 | declare class Path { 68 | start: Node; 69 | end: Node; 70 | segments: PathSegment[]; 71 | length: number; 72 | 73 | constructor(start: Node, end: Node, segments: PathSegment[]); 74 | } 75 | 76 | declare function isNode(obj: object): boolean; 77 | 78 | declare function isRelationship(obj: object): boolean; 79 | 80 | declare function isUnboundRelationship(obj: object): boolean; 81 | 82 | declare function isPath(obj: object): boolean; 83 | 84 | declare function isPathSegment(obj: object): boolean; 85 | 86 | export { 87 | Node, 88 | Relationship, 89 | UnboundRelationship, 90 | Path, 91 | PathSegment, 92 | isNode, 93 | isRelationship, 94 | isUnboundRelationship, 95 | isPath, 96 | isPathSegment, 97 | NumberOrInteger, 98 | StandardDate 99 | }; 100 | -------------------------------------------------------------------------------- /src/server/neo4j/types/result-summary.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Integer from "./integer"; 21 | import { NumberOrInteger } from "./graph-types"; 22 | 23 | declare interface ResultSummary { 24 | query: { text: string; parameters: { [key: string]: any } }; 25 | queryType: string; 26 | counters: QueryStatistic; 27 | plan: Plan; 28 | profile: ProfiledPlan; 29 | notifications: Notification[]; 30 | server: ServerInfo; 31 | resultConsumedAfter: T; 32 | resultAvailableAfter: T; 33 | 34 | hasPlan(): boolean; 35 | 36 | hasProfile(): boolean; 37 | } 38 | 39 | declare interface Plan { 40 | operatorType: string; 41 | identifiers: string[]; 42 | arguments: { [key: string]: string }; 43 | children: Plan[]; 44 | } 45 | 46 | declare interface ProfiledPlan { 47 | operatorType: string; 48 | identifiers: string[]; 49 | arguments: { [key: string]: string }; 50 | dbHits: number; 51 | rows: number; 52 | pageCacheMisses: number; 53 | pageCacheHits: number; 54 | pageCacheHitRatio: number; 55 | time: number; 56 | 57 | hasPageCacheStats(): boolean; 58 | 59 | children: ProfiledPlan[]; 60 | } 61 | 62 | declare interface QueryStatistic { 63 | containsUpdates(): boolean; 64 | 65 | containsSystemUpdates(): boolean; 66 | 67 | updates(): { [key: string]: number }; 68 | 69 | systemUpdates(): number; 70 | } 71 | 72 | declare type NotificationPosition = { 73 | offset: number; 74 | line: number; 75 | column: number; 76 | }; 77 | 78 | declare interface Notification { 79 | code: string; 80 | title: string; 81 | description: string; 82 | severity: string; 83 | position: NotificationPosition | {}; 84 | } 85 | 86 | declare interface ServerInfo { 87 | address: string; 88 | version: string; 89 | } 90 | 91 | declare const queryType: { 92 | READ_ONLY: "r"; 93 | READ_WRITE: "rw"; 94 | WRITE_ONLY: "w"; 95 | SCHEMA_WRITE: "s"; 96 | }; 97 | 98 | export { 99 | queryType, 100 | Plan, 101 | ProfiledPlan, 102 | QueryStatistic, 103 | Notification, 104 | ServerInfo, 105 | NotificationPosition 106 | }; 107 | 108 | export default ResultSummary; 109 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from "assert"; 2 | 3 | const { parseExtract } = require("../../modules/parseExtract"); 4 | const { extract } = require("../../modules/parseExtract"); 5 | const { OutlineProvider } = require("../../modules/OutlineProvider"); 6 | 7 | //import { expect } from "chai"; 8 | 9 | // You can import and use all API from the 'vscode' module 10 | // as well as import your extension to test it 11 | import * as vscode from "vscode"; 12 | // import * as myExtension from '../extension'; 13 | 14 | suite("Extension Test Suite", () => { 15 | vscode.window.showInformationMessage("Start all tests."); 16 | 17 | const exResultData = { 18 | graphOutline: [ 19 | { label: "Movie", properties: ["title", "tagline", "released"] }, 20 | { label: "Person", properties: ["born", "name"] } 21 | ], 22 | uniDirectionalRelationship: [ 23 | { 24 | originNode: ["Person"], 25 | relationship: "ACTED_IN", 26 | dependentNode: ["Movie"] 27 | }, 28 | { 29 | originNode: ["Person"], 30 | relationship: "ACTED_IN", 31 | dependentNode: ["Movie"] 32 | } 33 | ], 34 | biDirectionalRelationship: [] 35 | }; 36 | 37 | const testConfig = { 38 | activeSettings: { 39 | dbAddress: "bolt://localhost", 40 | username: "neo4j", 41 | password: "test" 42 | } 43 | }; 44 | 45 | test("Sample test", () => { 46 | assert.equal(-1, [1, 2, 3].indexOf(5)); 47 | assert.equal(-1, [1, 2, 3].indexOf(0)); 48 | }); 49 | 50 | test("Extract functionality", () => { 51 | const extractObj = extract("Trinity('Test') stuff"); 52 | assert.equal(extractObj.queryString, "Test"); 53 | assert.equal(extractObj.currIndex, 14); 54 | }); 55 | 56 | test("parseExtract functionality", () => { 57 | const queryArray = parseExtract( 58 | "Trinity('Test') stuff Trinity('anotherTest')" 59 | ); 60 | assert.equal(queryArray[0], "Test"); 61 | assert.equal(queryArray[1], "anotherTest"); 62 | }); 63 | //Testing OutlineProvier methods 64 | 65 | const outlineProvider = new OutlineProvider(undefined, testConfig); 66 | const exResultObj = outlineProvider.createResultObj(exResultData); 67 | 68 | test("OutlineProvider class", () => { 69 | assert.equal(exResultObj.Person.Properties[0], "born"); 70 | assert.equal(exResultObj.Movie.Properties[1], "tagline"); 71 | assert.equal(exResultObj.Person["Uni-Directional"].ACTED_IN[0], "Movie"); 72 | }); 73 | 74 | // testing setUpData method 75 | 76 | const treeData = outlineProvider.setUpData(exResultObj); 77 | 78 | test("setUpData method", () => { 79 | assert.equal(treeData[0].label, "Person"); 80 | assert.equal(treeData[0].children[0].label, "Uni-Directional"); 81 | assert.equal(treeData[0].children[0].children[0].label, "ACTED_IN"); 82 | assert.equal( 83 | treeData[0].children[0].children[0].children[0].label, 84 | "Movie" 85 | ); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /src/server/neo4j/types/driver.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Session from "./session"; 21 | import RxSession from "./session-rx"; 22 | import { Parameters } from "./query-runner"; 23 | import { Neo4jError } from "./error"; 24 | import { ServerInfo } from "./result-summary"; 25 | 26 | declare interface AuthToken { 27 | scheme: string; 28 | principal: string; 29 | credentials: string; 30 | realm?: string; 31 | parameters?: Parameters; 32 | } 33 | 34 | declare type EncryptionLevel = "ENCRYPTION_ON" | "ENCRYPTION_OFF"; 35 | declare type TrustStrategy = 36 | | "TRUST_ALL_CERTIFICATES" 37 | | "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES" 38 | | "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES"; 39 | 40 | declare type LogLevel = "error" | "warn" | "info" | "debug"; 41 | 42 | declare interface LoggingConfig { 43 | level?: LogLevel; 44 | logger: (level: LogLevel, message: string) => void; 45 | } 46 | 47 | declare interface Config { 48 | encrypted?: boolean | EncryptionLevel; 49 | trust?: TrustStrategy; 50 | trustedCertificates?: string[]; 51 | knownHosts?: string; 52 | fetchSize?: number; 53 | maxConnectionPoolSize?: number; 54 | maxTransactionRetryTime?: number; 55 | maxConnectionLifetime?: number; 56 | connectionAcquisitionTimeout?: number; 57 | connectionTimeout?: number; 58 | disableLosslessIntegers?: boolean; 59 | logging?: LoggingConfig; 60 | resolver?: (address: string) => string[] | Promise; 61 | } 62 | 63 | declare type SessionMode = "READ" | "WRITE"; 64 | 65 | declare const READ: SessionMode; 66 | declare const WRITE: SessionMode; 67 | 68 | declare interface Driver { 69 | session({ 70 | defaultAccessMode, 71 | bookmarks, 72 | database, 73 | fetchSize 74 | }?: { 75 | defaultAccessMode?: SessionMode; 76 | bookmarks?: string | string[]; 77 | fetchSize?: number; 78 | database?: string; 79 | }): Session; 80 | 81 | rxSession({ 82 | defaultAccessMode, 83 | bookmarks, 84 | database, 85 | fetchSize 86 | }?: { 87 | defaultAccessMode?: SessionMode; 88 | bookmarks?: string | string[]; 89 | fetchSize?: number; 90 | database?: string; 91 | }): RxSession; 92 | 93 | close(): Promise; 94 | 95 | verifyConnectivity(): Promise; 96 | 97 | supportsMultiDb(): Promise; 98 | } 99 | 100 | export { 101 | Driver, 102 | READ, 103 | WRITE, 104 | AuthToken, 105 | Config, 106 | EncryptionLevel, 107 | TrustStrategy, 108 | SessionMode 109 | }; 110 | 111 | export default Driver; 112 | -------------------------------------------------------------------------------- /src/modules/queryRunner.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { TrinityConfig } from "./readConfig"; 3 | const fs=require("fs"); 4 | const { parseExtract, extract }=require("./parseExtract"); 5 | import neo4j from "neo4j-driver"; 6 | const path=require("path"); 7 | 8 | export class QueryRunner { 9 | tChannel: vscode.OutputChannel; 10 | trinityConfig: TrinityConfig; 11 | 12 | constructor(trinityConfig: TrinityConfig) { 13 | this.trinityConfig=trinityConfig; 14 | this.tChannel=vscode.window.createOutputChannel("Trinity"); 15 | } 16 | // executes each the active file is saved 17 | handleSave(event: vscode.TextDocument) { 18 | // read in the active file 19 | const result=parseExtract(fs.readFileSync(event.fileName).toString()); 20 | // destructure the active settings from the .trinity.json file 21 | const { 22 | dbAddress, 23 | username, 24 | password, 25 | clearChannelOnSave, 26 | JSONOutputAbsolutePath, 27 | outputFilename 28 | }=this.trinityConfig.activeSettings||{}; 29 | // if required settings are not present, notify the user and end early 30 | if (!dbAddress||!username||!password) { 31 | vscode.window.showInformationMessage( 32 | "Trinity: Unable to run Trinity Queries. Please check your login credentials in the .trinity.json file." 33 | ); 34 | return; 35 | } 36 | // initialize connection to Neo4j DB 37 | const driver=neo4j.driver( 38 | dbAddress, 39 | neo4j.auth.basic(username, password) 40 | ); 41 | // clear tChanel based on active settigs 42 | if (clearChannelOnSave) { 43 | this.tChannel.clear(); 44 | } 45 | // create array to store return values from queries 46 | const promises=[]; 47 | // define output file location 48 | const outputPath=path.resolve(JSONOutputAbsolutePath, outputFilename); 49 | // iterate across the queries 50 | for (let query of result) { 51 | // create a Neo4j session to submit the query to 52 | const session=driver.session({ defaultAccessMode: neo4j.session.READ }); 53 | // only run valid queries 54 | if (!query) { 55 | this.tChannel.appendLine("Query skipped"); 56 | continue; 57 | } 58 | // push the query into promises array, once all queries are returned 59 | // the promises array will be written to a json file at the outputPath. 60 | promises.push( 61 | session 62 | .readTransaction(tx => tx.run(query)) 63 | .then(result => { 64 | this.tChannel.appendLine(query); 65 | this.tChannel.appendLine( 66 | `Result: ${JSON.stringify(result.records, null, 2)}` 67 | ); 68 | return result; 69 | }) 70 | .catch((err: Error): void => { 71 | vscode.window.showInformationMessage( 72 | "Trinity: Please check your query syntax." 73 | ); 74 | }) 75 | ); 76 | } 77 | 78 | Promise.all(promises).then(values => { 79 | const stringObj=JSON.stringify(values, null, 2); 80 | 81 | // only writes non empty objects to the outputPath. 82 | if (stringObj!=="[]") { 83 | fs.writeFile(outputPath, stringObj, "utf8", (err: Error) => { 84 | if (!err) { 85 | return; 86 | } 87 | vscode.window.showInformationMessage( 88 | "Trinity: Unable to save queries to output file" 89 | ); 90 | }); 91 | } 92 | }); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /resources/dark/number.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/number.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/dark/string.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/light/string.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/server/neo4j/types/temporal-types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import { NumberOrInteger, StandardDate } from "./graph-types"; 21 | import Integer from "./integer"; 22 | 23 | declare class Duration { 24 | readonly months: T; 25 | readonly days: T; 26 | readonly seconds: T; 27 | readonly nanoseconds: T; 28 | 29 | constructor(months: T, days: T, seconds: T, nanoseconds: T); 30 | } 31 | 32 | declare class LocalTime { 33 | readonly hour: T; 34 | readonly minute: T; 35 | readonly second: T; 36 | readonly nanosecond: T; 37 | 38 | constructor(hour: T, minute: T, second: T, nanosecond: T); 39 | 40 | static fromStandardDate( 41 | standardDate: StandardDate, 42 | nanosecond?: number 43 | ): LocalTime; 44 | } 45 | 46 | declare class Time { 47 | readonly hour: T; 48 | readonly minute: T; 49 | readonly second: T; 50 | readonly nanosecond: T; 51 | readonly timeZoneOffsetSeconds: T; 52 | 53 | constructor( 54 | hour: T, 55 | minute: T, 56 | second: T, 57 | nanosecond: T, 58 | timeZoneOffsetSeconds: T 59 | ); 60 | 61 | static fromStandardDate( 62 | standardDate: StandardDate, 63 | nanosecond?: number 64 | ): Time; 65 | } 66 | 67 | declare class Date { 68 | readonly year: T; 69 | readonly month: T; 70 | readonly day: T; 71 | 72 | constructor(year: T, month: T, day: T); 73 | 74 | static fromStandardDate(standardDate: StandardDate): Date; 75 | } 76 | 77 | declare class LocalDateTime { 78 | readonly year: T; 79 | readonly month: T; 80 | readonly day: T; 81 | readonly hour: T; 82 | readonly minute: T; 83 | readonly second: T; 84 | readonly nanosecond: T; 85 | 86 | constructor( 87 | year: T, 88 | month: T, 89 | day: T, 90 | hour: T, 91 | minute: T, 92 | second: T, 93 | nanosecond: T 94 | ); 95 | 96 | static fromStandardDate( 97 | standardDate: StandardDate, 98 | nanosecond?: number 99 | ): LocalDateTime; 100 | } 101 | 102 | declare class DateTime { 103 | readonly year: T; 104 | readonly month: T; 105 | readonly day: T; 106 | readonly hour: T; 107 | readonly minute: T; 108 | readonly second: T; 109 | readonly nanosecond: T; 110 | readonly timeZoneOffsetSeconds?: T; 111 | readonly timeZoneId?: string; 112 | 113 | constructor( 114 | year: T, 115 | month: T, 116 | day: T, 117 | hour: T, 118 | minute: T, 119 | second: T, 120 | nanosecond: T, 121 | timeZoneOffsetSeconds?: T, 122 | timeZoneId?: string 123 | ); 124 | 125 | static fromStandardDate( 126 | standardDate: StandardDate, 127 | nanosecond?: number 128 | ): DateTime; 129 | } 130 | 131 | declare function isDuration(obj: object): boolean; 132 | 133 | declare function isLocalTime(obj: object): boolean; 134 | 135 | declare function isTime(obj: object): boolean; 136 | 137 | declare function isDate(obj: object): boolean; 138 | 139 | declare function isLocalDateTime(obj: object): boolean; 140 | 141 | declare function isDateTime(obj: object): boolean; 142 | 143 | export { 144 | Duration, 145 | LocalTime, 146 | Time, 147 | Date, 148 | LocalDateTime, 149 | DateTime, 150 | isDuration, 151 | isLocalTime, 152 | isTime, 153 | isDate, 154 | isLocalDateTime, 155 | isDateTime 156 | }; 157 | -------------------------------------------------------------------------------- /src/server/neo4j/types/integer.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | declare class Integer { 21 | low: number; 22 | high: number; 23 | 24 | constructor(low?: number, high?: number); 25 | 26 | inSafeRange(): boolean; 27 | 28 | toInt(): number; 29 | 30 | toNumber(): number; 31 | 32 | toString(radix: number): string; 33 | 34 | getHighBits(): number; 35 | 36 | getLowBits(): number; 37 | 38 | getNumBitsAbs(): number; 39 | 40 | isZero(): boolean; 41 | 42 | isNegative(): boolean; 43 | 44 | isPositive(): boolean; 45 | 46 | isOdd(): boolean; 47 | 48 | isEven(): boolean; 49 | 50 | equals(other: Integer | number | string): boolean; 51 | 52 | notEquals(other: Integer | number | string): boolean; 53 | 54 | lessThan(other: Integer | number | string): boolean; 55 | 56 | lessThanOrEqual(other: Integer | number | string): boolean; 57 | 58 | greaterThan(other: Integer | number | string): boolean; 59 | 60 | greaterThanOrEqual(other: Integer | number | string): boolean; 61 | 62 | compare(other: Integer | number | string): number; 63 | 64 | negate(): Integer; 65 | 66 | add(addend: Integer | number | string): Integer; 67 | 68 | subtract(subtrahend: Integer | number | string): Integer; 69 | 70 | multiply(multiplier: Integer | number | string): Integer; 71 | 72 | div(divisor: Integer | number | string): Integer; 73 | 74 | modulo(divisor: Integer | number | string): Integer; 75 | 76 | not(): Integer; 77 | 78 | and(other: Integer | number | string): Integer; 79 | 80 | or(other: Integer | number | string): Integer; 81 | 82 | xor(other: Integer | number | string): Integer; 83 | 84 | shiftLeft(numBits: Integer | number): Integer; 85 | 86 | shiftRight(numBits: Integer | number): Integer; 87 | 88 | static __isInteger__: true; 89 | 90 | static isInteger(obj: object): boolean; 91 | 92 | static fromInt(value: number): Integer; 93 | 94 | static fromNumber(value: number): Integer; 95 | 96 | static fromBits(lowBits: number, highBits: number): Integer; 97 | 98 | static fromString(str: string, radix?: number): Integer; 99 | 100 | static fromValue( 101 | value: Integer | number | string | { low: number; high: number } 102 | ): Integer; 103 | 104 | static toNumber( 105 | value: Integer | number | string | { low: number; high: number } 106 | ): number; 107 | 108 | static toString( 109 | value: Integer | number | string | { low: number; high: number }, 110 | radix?: number 111 | ): string; 112 | 113 | static inSafeRange( 114 | value: Integer | number | string | { low: number; high: number } 115 | ): boolean; 116 | 117 | static ZERO: Integer; 118 | static ONE: Integer; 119 | static NEG_ONE: Integer; 120 | static MAX_VALUE: Integer; 121 | static MIN_VALUE: Integer; 122 | static MIN_SAFE_VALUE: Integer; 123 | static MAX_SAFE_VALUE: Integer; 124 | } 125 | 126 | declare function int( 127 | value: Integer | number | string | { low: number; high: number } 128 | ): Integer; 129 | 130 | declare function isInt(obj: object): boolean; 131 | 132 | declare function inSafeRange( 133 | val: Integer | number | string | { low: number; high: number } 134 | ): boolean; 135 | 136 | declare function toNumber( 137 | val: Integer | number | string | { low: number; high: number } 138 | ): number; 139 | 140 | declare function toString( 141 | val: Integer | number | string | { low: number; high: number }, 142 | radix?: number 143 | ): string; 144 | 145 | export { int, isInt, inSafeRange, toNumber, toString }; 146 | 147 | export default Integer; 148 | -------------------------------------------------------------------------------- /src/modules/parseExtract.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * ParseExtract accepts file contents as giant string and recursively calls extract function until Trinity queries are not found 3 | * within the string argument and returns an array of Cypher queries. 4 | * 5 | * findQuery: locates each instance of Trinity keyword (which contains a query) and recursively calls extract until Trinity queries are not found 6 | * 7 | * Extract: processes each query within Trinity function 8 | * @param string 9 | * 10 | */ 11 | 12 | function parseExtract(string: string): Array { 13 | // Array for storing the Queries inside the string 14 | let array: Array = []; 15 | 16 | // Find queries inside of string, push them on to array 17 | const findQuery = (string: string) => { 18 | // find the location of trinity in the string 19 | const tlocation: number = string.search("Trinity"); 20 | 21 | // if 0, Trinity hasn't been typed into the string 22 | if (tlocation !== -1) { 23 | // Create new string, which will be result of slicing from 'T' in Trinity 24 | let newString: string = string.slice(tlocation, string.length); 25 | 26 | //Create new variable for the query and end location 27 | //extract(newString) returns an object 28 | let queryNLocation: { 29 | queryString: string | boolean; 30 | currIndex: number; 31 | } = extract(newString); 32 | 33 | // push the query onto the main array 34 | array.push(queryNLocation.queryString); 35 | 36 | // recursively call the function find Query on the new string based on the location 37 | let remainingString: string = newString.slice( 38 | queryNLocation.currIndex + 1 39 | ); 40 | 41 | // recursively call the function on the new string 42 | findQuery(remainingString); 43 | } 44 | }; 45 | 46 | findQuery(string); 47 | return array; 48 | } 49 | 50 | const extract = ( 51 | string: string 52 | ): { queryString: string | boolean; currIndex: number } => { 53 | const brackets: { [key: string]: string } = { 54 | "[": "PUSH TO STACK", 55 | "{": "PUSH TO STACK", 56 | "(": "PUSH TO STACK", 57 | "'": "'", 58 | '"': '"', 59 | "`": "`", 60 | "]": "[", 61 | "}": "{", 62 | ")": "(" 63 | }; 64 | 65 | // extract the query 66 | let stack: Array = [string[8]]; 67 | let currIndex: number = 9; 68 | let queryString: string | boolean = ""; 69 | 70 | // iterate until empty the stack, or find incorrect brackets 71 | while (stack.length > 0) { 72 | // store current char 73 | const currChar: string = string[currIndex]; 74 | // store the brack[curChar] 75 | const bracket: string | undefined = brackets[currChar]; 76 | // If the variable in brackets obj 77 | // CASE: Not a bracket => Go to next loop 78 | if (!bracket) { 79 | queryString += currChar; 80 | currIndex += 1; 81 | continue; 82 | } 83 | // CASE: PUSH TO STACK => Push it to the stack 84 | else if (bracket === "PUSH TO STACK") { 85 | stack.push(currChar); 86 | } 87 | // CASE: Else => pop it 88 | // CASE: currChar is quote and top of stack is not the same quote -> push it to stack 89 | else if (currChar === '"' || currChar === "'" || currChar === "`") { 90 | // CASE: currChar is quote and top of stack is the same quote -> pop from stack 91 | if (stack[stack.length - 1] === currChar) { 92 | stack.pop(); 93 | } else { 94 | stack.push(currChar); 95 | } 96 | } 97 | // CASE: Closing Bracket & compliments top of stack -> pop from stack 98 | else if (currChar === "]" || currChar === "}" || currChar === ")") { 99 | if (stack[stack.length - 1] === bracket) { 100 | stack.pop(); 101 | } else { 102 | // CASE: Closing Bracket & does not compliment top of stack -> return false and curr location 103 | queryString = false; 104 | break; 105 | } 106 | } 107 | // prepare for next iteration 108 | currIndex += 1; 109 | if (stack.length > 0) { 110 | queryString += currChar; 111 | } 112 | } 113 | return { 114 | queryString: queryString, 115 | currIndex: currIndex 116 | }; 117 | }; 118 | 119 | module.exports = { parseExtract, extract }; 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Trinity 6 | 7 | ## What is Trinity? 8 | 9 | Trinity is a VS Code extension for previewing Neo4j queries and database structure within the VS Code environment. Trinity intends to remove the need for switching between VS Code and Neo4j Desktop or Neo4j Browser during the development process. 10 | 11 | ## Features 12 | 13 | ### **Core Features** 14 | 15 | 1. Connects to a user's Neo4j database and displays the graph database structure (Node Labels, Properties and Unidirectional/Bidirectional relationships). 16 | 2. Parses Neo4j/Cypher queries/mutations that are typed into the current open document in VS Code. 17 | 3. Sends the queries/mutations to a database as defined in the user's configuration file . 18 | 4. Renders the responses to the Trinity output channel on VS Code. 19 | 5. Optionally writes the output to a local JSON file based on the user's configuration. 20 | 21 | demo gif 22 | 23 | ## Getting Started 24 | 25 | ### **Installation** 26 | 27 | Trinity can be installed from the VS Code Extensions marketplace [here](https://marketplace.visualstudio.com/items?itemName=Trinity.trinity). 28 | 29 | ### **Setting up the config file** 30 | 31 | In your working directory create a 32 | `.trinity.json` file. The following configuration options are available for setup by the user: 33 | 34 | ```json 35 | { 36 | "dbAddress": "bolt://localhost", 37 | "username": "neo4j", 38 | "password": "test", 39 | "clearChannelOnSave": true, 40 | "writeOutputToJSON": true, 41 | "JSONOutputRelativePath": "./", 42 | "outputFilename": "output.json" 43 | } 44 | ``` 45 | 46 | Required Settings: `dbAddess`, `username` and `password`. 47 | 48 | Default settings when not defined in the configuration file: 49 | 50 | ```json 51 | { 52 | "clearChannelOnSave": false, 53 | "writeOutputToJSON": false, 54 | "JSONOutputRelativePath": "./", 55 | "outputFilename": "output.json" 56 | } 57 | ``` 58 | 59 | ## Write and Invoking your first Trinity query 60 | 61 | To activate the extension and connect to your Neo4j Database: 62 | 63 | 1. Search for Trinity from the command palette in VS Code (Cmd/Ctrl + Shift + P) and run the _`Trinity: Run Trinity`_ command. 64 | 2. To deactivate, search for Trinity from the command palette in VS Code (Cmd/Ctrl + Shift + P) and run the _`Trinity: Deactivate Trinity`_ command. 65 | 66 | The following steps are required to setup a `Trinity` query inside your working file. 67 | 68 | 1. Create a function declaration for your `Trinity` query 69 | 2. Invoke your Cypher Query within a Trinity function invocation\* 70 | 3. On every save, Trinity will send any requests inside of the `Trinity` functions to your Neo4j Database and show responses in the Trinity Output Channel. To send another request, create a new invocation of the `Trinity` function and put the new request as the argument. Output will also be saved to a JSON file if setup in the configuration file. 71 | 72 | _\*Multiple queries may be invoked within a single file. Current functionality does not support the passing of variables or parameterized queries._ 73 | 74 | --- 75 | 76 | ### Sample Python Setup 77 | 78 | ```python 79 | # Create a Trinity function definition in your working file. 80 | def Trinity (): 81 | return 82 | 83 | # Anywhere in your open file, put a Neo4j Cypher query inside the Trinity function. For example: 84 | Trinity('Match (n{name: "Carrie-Anne Moss"}) Return n') 85 | ``` 86 | 87 | ### Sample JavaScript Setup 88 | 89 | ```javascript 90 | // Create a Trinity function definition in your working file. 91 | function Trinity() {} 92 | 93 | // Anywhere in your open file, put a Neo4j Cypher query inside the Trinity function. For example: 94 | Trinity('Match (n{name: "Carrie-Anne Moss"}) Return n'); 95 | ``` 96 | 97 | On every save, Trinity will send any requests inside of the `Trinity` functions to your Neo4j Database and show responses in the Trinity Output Channel. To send another request, create a new invocation of the `Trinity` function and put the new request as the argument. 98 | 99 | --- 100 | 101 | ## Contributing and Issues 102 | 103 | We are always looking to improve. If there are any contributions, feature requests or issues/bugs you have, please check out our documentation on [contributions](./DOCUMENTATION/docs/contributing.md), [feature requests](./DOCUMENTATION/docs/featureRequest.md) or [issues/bugs](./DOCUMENTATION/docs/bugReport.md). 104 | 105 | ## Release Notes 106 | 107 | Created by: Alex Bednarek, Alex Drew, Connor Bovino, Olena Danykh 108 | 109 | 0.0.1 | Initial release of Trinity, More to come! 110 | -------------------------------------------------------------------------------- /src/server/neo4j/graphdb-outline-ts.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import neo4j from "neo4j-driver"; 3 | import { QueryResult } from "./types/index"; 4 | import { Driver } from "./types/driver"; 5 | import Session from "./types/session"; 6 | import Transaction from "./types/transaction"; 7 | 8 | interface GraphOutline { 9 | label: string; 10 | properties: string[]; 11 | } 12 | 13 | interface Relationships { 14 | originNode: string[]; 15 | relationship: string; 16 | dependentNode: string[]; 17 | } 18 | 19 | export interface GraphStructure { 20 | graphOutline: Array; 21 | uniDirectionalRelationship: Array; 22 | biDirectionalRelationship: Array; 23 | } 24 | 25 | /** 26 | * * Graph DB Concepts: 27 | * https://neo4j.com/docs/getting-started/current/graphdb-concepts/ 28 | * 29 | * * One Directional Relationships: 30 | * https://stackoverflow.com/questions/44481032/find-only-single-direction-relation-in-neo4j 31 | * MATCH (a) -[r] -> (b) 32 | * WHERE NOT (b) -[]-> (a) 33 | * RETURN DISTINCT labels(a), type(r), labels(b) 34 | * 35 | * * Two Directional Relationships: 36 | * MATCH (a) -[r] -> (b) 37 | * WHERE (b) -[]-> (a) 38 | * RETURN DISTINCT labels(a), type(r), labels(b) 39 | * 40 | * * Get all Properties and keys for an entire graph 41 | * https://stackoverflow.com/questions/48993061/how-can-i-get-all-property-keys-for-all-nodes-or-for-a-given-label-with-cypher 42 | * MATCH(n) 43 | * WITH LABELS(n) AS labels , KEYS(n) AS keys 44 | * UNWIND labels AS label 45 | * UNWIND keys AS key 46 | * RETURN DISTINCT label, COLLECT(DISTINCT key) AS props 47 | * ORDER BY label 48 | * 49 | * * High Level Inventory 50 | * https://neo4j.com/developer/kb/how-to-get-a-high-level-inventory-of-objects-in-your-graph/ 51 | * 52 | * * Parameterized neo4j Queries in Node.js 53 | * * (not currently used. will be for trinity function) 54 | * https://www.youtube.com/watch?v=snjnJCZhXUM&t=905s 55 | */ 56 | 57 | /** 58 | * connects to a neo4j database and return a promis that resolves to 59 | * an object containing the following: 60 | * - labels & property keys 61 | * - unidirectional relationships 62 | * - bidrection relationship 63 | * 64 | * @param {String} dbAddress - location of the neo4j database 65 | * @param {String} user - username to access database 66 | * @param {String} pass - password to access database 67 | */ 68 | export const getGraphStructure=async ( 69 | dbAddress: string, 70 | user: string, 71 | pass: string 72 | ): Promise => { 73 | // create a connection to your neo4j database 74 | // handles basic authentication and connects to a local host 75 | const driver: any=neo4j.driver(dbAddress, neo4j.auth.basic(user, pass)); 76 | 77 | // initialize a query session 78 | const session: Session=driver.session(); 79 | // begin a transaction in order to send multiple queries 80 | // in a single session. 81 | const txc: Transaction=session.beginTransaction(); 82 | 83 | const queries: { [key: string]: string }={ 84 | getOutline: ` 85 | MATCH(n) 86 | WITH LABELS(n) AS labels , KEYS(n) AS keys 87 | UNWIND labels AS label 88 | UNWIND keys AS key 89 | RETURN DISTINCT label, COLLECT(DISTINCT key) AS props 90 | ORDER BY label`, 91 | getUniDirectionalRelationships: ` 92 | MATCH (a) -[r] -> (b) 93 | WHERE NOT (b) -[]-> (a) 94 | RETURN DISTINCT labels(a), type(r), labels(b)`, 95 | getBiDirectionalRelationships: ` 96 | MATCH (a) -[r] -> (b) 97 | WHERE (b) -[]-> (a) 98 | RETURN DISTINCT labels(a), type(r), labels(b)` 99 | }; 100 | 101 | try { 102 | //get graph outline of labels and properties 103 | const graphOutlineRaw: QueryResult=await txc.run(queries.getOutline); 104 | const graphOutlineFormat: Array=graphOutlineRaw.records.map( 105 | el => ({ 106 | label: el._fields[0], 107 | properties: el._fields[1] 108 | }) 109 | ); 110 | 111 | //get uni-directional relationships 112 | const uniDirectionalRaw: QueryResult=await txc.run( 113 | queries.getUniDirectionalRelationships 114 | ); 115 | const uniDirectionalFormat: Array=uniDirectionalRaw.records.map( 116 | el => ({ 117 | originNode: el._fields[0], 118 | relationship: el._fields[1], 119 | dependentNode: el._fields[2] 120 | }) 121 | ); 122 | 123 | //get bi-directional relationships 124 | const biDirectionalRaw: QueryResult=await txc.run( 125 | queries.getBiDirectionalRelationships 126 | ); 127 | const biDirectionalFormat: Array=biDirectionalRaw.records.map( 128 | el => ({ 129 | originNode: el._fields[0], 130 | relationship: el._fields[1], 131 | dependentNode: el._fields[2] 132 | }) 133 | ); 134 | 135 | // Return quieried data in a single object 136 | return { 137 | graphOutline: graphOutlineFormat, 138 | uniDirectionalRelationship: uniDirectionalFormat, 139 | biDirectionalRelationship: biDirectionalFormat 140 | }; 141 | } catch (error) { 142 | vscode.window.showInformationMessage( 143 | "Please confirm your database is up and running and restart your Trinity Extension." 144 | ); 145 | } finally { 146 | // to end exucution we must close the driver and session 147 | // otherwise execution context will be left hanging 148 | session.close(); 149 | driver.close(); 150 | vscode.window.showInformationMessage( 151 | "Trinity: Your Graph Outline is up to Date!" 152 | ); 153 | } 154 | }; 155 | -------------------------------------------------------------------------------- /src/modules/readConfig.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable curly */ 2 | import * as vscode from "vscode"; 3 | import * as path from "path"; 4 | import * as fs from "fs"; 5 | import * as find from "find"; 6 | 7 | interface TrinitySettings { 8 | dbAddress: string; 9 | username: string; 10 | password: string; 11 | clearChannelOnSave?: boolean; // -> Default to false 12 | writeOutputToJSON?: boolean; // -> Default to false 13 | JSONOutputRelativePath?: string; // -> Default to './' 14 | JSONOutputAbsolutePath?: string; // -> relative to the config file 15 | outputFilename?: string; // -> default to the output.json 16 | } 17 | 18 | export class TrinityConfig { 19 | activeWorkspaceName?: string; 20 | activeWorkspacePath?: string; 21 | configFilePath?: string; 22 | configFilePathRoot?: string; 23 | configWatcher?: fs.FSWatcher; 24 | activeSettings?: TrinitySettings; 25 | 26 | constructor() { 27 | this.getSettings = this.getSettings.bind(this); 28 | } 29 | 30 | findFileInParentDirectory( 31 | startingDirectory: string, 32 | fileName: string 33 | ): string | undefined { 34 | let currPath: string = startingDirectory; 35 | const rootDir: string = path.parse(process.cwd()).root; 36 | // iterate through parent directory untill reach the root 37 | while (currPath !== rootDir) { 38 | // get all files and folders in current directory 39 | const files: string[] = fs.readdirSync(currPath, { 40 | encoding: "utf8", 41 | withFileTypes: false 42 | }); 43 | // iterate through files, looking for the configuration file 44 | for (let file of files) { 45 | if (file === fileName) { 46 | return path.resolve(currPath, file); 47 | } 48 | } 49 | // if config file is not in the current directory, 50 | // then check current directory's parents 51 | currPath = path.resolve(currPath, "../"); 52 | } 53 | // will return undefined if config file is not found 54 | } 55 | 56 | getSettingsPath(directoryName: string, fileName: string): string | undefined { 57 | //recursively look for config file inside sub directories 58 | let configPathSubdirectory: string[] = find.fileSync( 59 | fileName, 60 | directoryName 61 | ); 62 | if (configPathSubdirectory.length > 0) { 63 | return configPathSubdirectory[0]; 64 | } 65 | //if config is not in sub directory recursively look in the parent directories 66 | return this.findFileInParentDirectory(directoryName, fileName); 67 | } 68 | 69 | getSettings(): void { 70 | const filePath = this.configFilePath; 71 | if (!filePath) return; 72 | const trinityConfigString: string = fs.readFileSync(filePath, "utf-8"); 73 | const trinityConfig: TrinitySettings = JSON.parse(trinityConfigString); 74 | 75 | this.activeSettings = trinityConfig; 76 | // default settings 77 | if (!this.activeSettings.clearChannelOnSave) { 78 | this.activeSettings.clearChannelOnSave = false; 79 | } 80 | if (!this.activeSettings.writeOutputToJSON) { 81 | this.activeSettings.writeOutputToJSON = false; 82 | } 83 | if (!this.activeSettings.JSONOutputRelativePath) { 84 | this.activeSettings.JSONOutputRelativePath = "./"; 85 | } 86 | if (!this.activeSettings.outputFilename) { 87 | this.activeSettings.outputFilename = "output.json"; 88 | } 89 | if ( 90 | this.configFilePathRoot && 91 | this.activeSettings && 92 | this.activeSettings.JSONOutputRelativePath 93 | ) { 94 | trinityConfig.JSONOutputAbsolutePath = path.resolve( 95 | this.configFilePathRoot, 96 | this.activeSettings.JSONOutputRelativePath 97 | ); 98 | } 99 | } 100 | 101 | watchConfig(): void { 102 | // Kill current watch if already in progress 103 | if (this.configWatcher) this.configWatcher.close(); 104 | 105 | // Initialize new watcher and store as this.configWatcher 106 | if (!this.configFilePath) return; 107 | this.configWatcher = fs.watch(this.configFilePath, () => { 108 | // each time config file save, refresh configuration settigs 109 | this.getSettings(); 110 | }); 111 | } 112 | 113 | async getActiveWorkspace(): Promise { 114 | // find all the current active workspaces 115 | const activeWorkspaces: vscode.WorkspaceFolder[] | undefined = 116 | vscode.workspace.workspaceFolders; 117 | let quickPicks: string[] = []; 118 | 119 | // convert active workspaces to format for quickpick dropdown 120 | if (activeWorkspaces) { 121 | quickPicks = activeWorkspaces.map( 122 | (el, index) => `${index + 1}. ${el.name}` 123 | ); 124 | } 125 | 126 | // prompt the user for the current active workspace 127 | vscode.window.showInformationMessage( 128 | "Trinity: Please select your Active Workspace" 129 | ); 130 | return vscode.window 131 | .showQuickPick(quickPicks, { 132 | placeHolder: "Trinity: Please Select the Active Workspace" 133 | }) 134 | .then(res => { 135 | if (!res || !activeWorkspaces) return; 136 | // stores user's selection and path on 'this' 137 | this.quickPickHandler(res, activeWorkspaces); 138 | }); 139 | } 140 | 141 | quickPickHandler(res: string, activeWorkspaces: vscode.WorkspaceFolder[]) { 142 | // get index of user's selection 143 | const index: number = parseInt(res.split(".")[0]) - 1; 144 | 145 | // store workspace name and filepath 146 | this.activeWorkspaceName = res; 147 | this.activeWorkspacePath = activeWorkspaces[index]["uri"]["fsPath"]; 148 | 149 | // find the closest config file 150 | this.configFilePath = this.getSettingsPath( 151 | this.activeWorkspacePath, 152 | ".trinity.json" 153 | ); 154 | // get file path of the config file 155 | if (this.configFilePath) { 156 | this.configFilePathRoot = this.configFilePath.replace( 157 | ".trinity.json", 158 | "" 159 | ); 160 | } 161 | // begin watching the config file 162 | this.watchConfig(); 163 | this.getSettings(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/server/neo4j/types/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2002-2019 "Neo4j," 3 | * Neo4j Sweden AB [http://neo4j.com] 4 | * 5 | * This file is part of Neo4j. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | import Integer, { 21 | inSafeRange, 22 | int, 23 | isInt, 24 | toNumber, 25 | toString 26 | } from "./integer"; 27 | import { 28 | Node, 29 | Path, 30 | PathSegment, 31 | Relationship, 32 | UnboundRelationship 33 | } from "./graph-types"; 34 | import { isPoint, Point } from "./spatial-types"; 35 | import { 36 | Date, 37 | DateTime, 38 | Duration, 39 | isDate, 40 | isDateTime, 41 | isDuration, 42 | isLocalDateTime, 43 | isLocalTime, 44 | isTime, 45 | LocalDateTime, 46 | LocalTime, 47 | Time 48 | } from "./temporal-types"; 49 | import { 50 | Neo4jError, 51 | PROTOCOL_ERROR, 52 | SERVICE_UNAVAILABLE, 53 | SESSION_EXPIRED 54 | } from "./error"; 55 | import Result, { ResultObserver, QueryResult } from "./result"; 56 | import ResultSummary, { 57 | Notification, 58 | NotificationPosition, 59 | Plan, 60 | ProfiledPlan, 61 | ServerInfo, 62 | QueryStatistic 63 | } from "./result-summary"; 64 | import Record from "./record"; 65 | import Session from "./session"; 66 | import { 67 | AuthToken, 68 | Config, 69 | Driver, 70 | EncryptionLevel, 71 | READ, 72 | SessionMode, 73 | TrustStrategy, 74 | WRITE 75 | } from "./driver"; 76 | import Transaction from "./transaction"; 77 | import { Parameters } from "./query-runner"; 78 | 79 | declare const auth: { 80 | basic: (username: string, password: string, realm?: string) => AuthToken; 81 | 82 | kerberos: (base64EncodedTicket: string) => AuthToken; 83 | 84 | custom: ( 85 | principal: string, 86 | credentials: string, 87 | realm: string, 88 | scheme: string, 89 | parameters?: Parameters 90 | ) => AuthToken; 91 | }; 92 | 93 | declare function driver( 94 | url: string, 95 | authToken?: AuthToken, 96 | config?: Config 97 | ): Driver; 98 | 99 | declare const types: { 100 | Node: Node; 101 | Relationship: Relationship; 102 | UnboundRelationship: UnboundRelationship; 103 | PathSegment: PathSegment; 104 | Path: Path; 105 | Result: Result; 106 | ResultSummary: ResultSummary; 107 | Record: Record; 108 | Point: typeof Point; 109 | Duration: typeof Duration; 110 | LocalTime: typeof LocalTime; 111 | Time: typeof Time; 112 | Date: typeof Date; 113 | LocalDateTime: typeof LocalDateTime; 114 | DateTime: typeof DateTime; 115 | Integer: typeof Integer; 116 | }; 117 | 118 | declare const session: { 119 | READ: typeof READ; 120 | WRITE: typeof WRITE; 121 | }; 122 | 123 | declare const error: { 124 | SERVICE_UNAVAILABLE: typeof SERVICE_UNAVAILABLE; 125 | SESSION_EXPIRED: typeof SESSION_EXPIRED; 126 | PROTOCOL_ERROR: typeof PROTOCOL_ERROR; 127 | }; 128 | 129 | declare const integer: { 130 | toNumber: typeof toNumber; 131 | toString: typeof toString; 132 | inSafeRange: typeof inSafeRange; 133 | }; 134 | 135 | declare const spatial: { 136 | isPoint: typeof isPoint; 137 | }; 138 | 139 | declare const temporal: { 140 | isDuration: typeof isDuration; 141 | isLocalTime: typeof isLocalTime; 142 | isTime: typeof isTime; 143 | isDate: typeof isDate; 144 | isLocalDateTime: typeof isLocalDateTime; 145 | isDateTime: typeof isDateTime; 146 | }; 147 | 148 | /* 149 | Both default and non-default exports declare all visible types so that they can be used in client code like this: 150 | 151 | import neo4j from "neo4j-driver"; 152 | const driver: neo4j.Driver = neo4j.driver("bolt://localhost"); 153 | const session: neo4j.Session = driver.session(); 154 | ... 155 | */ 156 | 157 | declare const forExport: { 158 | driver: typeof driver; 159 | int: typeof int; 160 | isInt: typeof isInt; 161 | integer: typeof integer; 162 | auth: typeof auth; 163 | types: typeof types; 164 | session: typeof session; 165 | error: typeof error; 166 | spatial: typeof spatial; 167 | temporal: typeof temporal; 168 | Driver: Driver; 169 | AuthToken: AuthToken; 170 | Config: Config; 171 | EncryptionLevel: EncryptionLevel; 172 | TrustStrategy: TrustStrategy; 173 | SessionMode: SessionMode; 174 | Neo4jError: Neo4jError; 175 | Node: Node; 176 | Relationship: Relationship; 177 | UnboundRelationship: UnboundRelationship; 178 | PathSegment: PathSegment; 179 | Path: Path; 180 | Integer: Integer; 181 | Record: Record; 182 | Result: Result; 183 | QueryResult: QueryResult; 184 | ResultObserver: ResultObserver; 185 | ResultSummary: ResultSummary; 186 | Plan: Plan; 187 | ProfiledPlan: ProfiledPlan; 188 | QueryStatistic: QueryStatistic; 189 | Notification: Notification; 190 | ServerInfo: ServerInfo; 191 | NotificationPosition: NotificationPosition; 192 | Session: Session; 193 | Transaction: Transaction; 194 | Point: Point; 195 | isPoint: typeof isPoint; 196 | Duration: Duration; 197 | LocalTime: LocalTime; 198 | Time: Time; 199 | Date: Date; 200 | LocalDateTime: LocalDateTime; 201 | DateTime: DateTime; 202 | isDuration: typeof isDuration; 203 | isLocalTime: typeof isLocalTime; 204 | isTime: typeof isTime; 205 | isDate: typeof isDate; 206 | isLocalDateTime: typeof isLocalDateTime; 207 | isDateTime: typeof isDateTime; 208 | }; 209 | 210 | export { 211 | driver, 212 | int, 213 | isInt, 214 | integer, 215 | auth, 216 | types, 217 | session, 218 | error, 219 | spatial, 220 | temporal, 221 | Driver, 222 | AuthToken, 223 | Config, 224 | EncryptionLevel, 225 | TrustStrategy, 226 | SessionMode, 227 | Neo4jError, 228 | Node, 229 | Relationship, 230 | UnboundRelationship, 231 | PathSegment, 232 | Path, 233 | Integer, 234 | Record, 235 | Result, 236 | QueryResult, 237 | ResultObserver, 238 | ResultSummary, 239 | Plan, 240 | ProfiledPlan, 241 | QueryStatistic, 242 | Notification, 243 | ServerInfo, 244 | NotificationPosition, 245 | Session, 246 | Transaction, 247 | Point, 248 | isPoint, 249 | Duration, 250 | LocalTime, 251 | Time, 252 | Date, 253 | LocalDateTime, 254 | DateTime, 255 | isDuration, 256 | isLocalTime, 257 | isTime, 258 | isDate, 259 | isLocalDateTime, 260 | isDateTime 261 | }; 262 | 263 | export default forExport; 264 | -------------------------------------------------------------------------------- /src/modules/OutlineProvider.ts: -------------------------------------------------------------------------------- 1 | import * as vscode from "vscode"; 2 | import { 3 | getGraphStructure, 4 | GraphStructure 5 | } from "../server/neo4j/graphdb-outline-ts"; 6 | 7 | /** 8 | * Relation: Interface for all properties and dependent nodes 9 | * 10 | * ResultObject: Interface for all nodes and their properties and relationships 11 | * 12 | */ 13 | 14 | interface Relation { 15 | [key: string]: string[]; 16 | } 17 | 18 | interface ResultObject { 19 | [index: string]: { 20 | Properties: string[]; 21 | "Uni-Directional": Relation; 22 | "Bi-Directional": Relation; 23 | }; 24 | } 25 | 26 | /** 27 | * 28 | * OutlineProvider Class: Models outline structure utlilizing both VSCode methods and our own methods. Within this object 29 | * an asyncronous call is made to database, after which we used the createResultObj method to format our data. 30 | * Finally, we use the TreeTask class to create the exact format for VSCode to provide an outline view. 31 | * 32 | * TreeTask Class: Extends vscode tree item and allows us to create types for the specific items that will make up our outline view 33 | * 34 | */ 35 | export class OutlineProvider implements vscode.TreeDataProvider { 36 | // The following methods must be fired whenever tree data changes in order to see the change in our outline view 37 | // Private referring to the fact that it cannot be accessed outside the object 38 | private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); 39 | // Readonly referring to the fact that it cannot be changed 40 | readonly onDidChangeTreeData: vscode.Event = this 41 | ._onDidChangeTreeData.event; 42 | // Array of tree tasks used to populate outline view 43 | data: TreeTask[] = []; 44 | 45 | /** 46 | * Trinity config inherits the class that reads the user's login/database information 47 | * Constructor executes create graph structure which fills the OutlineProvider with data 48 | */ 49 | trinityConfig: any; 50 | constructor(private context: vscode.ExtensionContext, trinityConfig: any) { 51 | this.trinityConfig = trinityConfig; 52 | this.createGraphStructure(); 53 | } 54 | 55 | /** 56 | * createResultObj method accepts result data as arg from call to database and re-structures the returned data so that it can be easily 57 | * manipulated to create outline view 58 | * @param resultData 59 | */ 60 | 61 | createResultObj(resultData: GraphStructure) { 62 | // Create Result Obj 63 | const resultObj: ResultObject = {}; 64 | // UniDirectional 65 | for (let i = 0; i < resultData.uniDirectionalRelationship.length; i += 1) { 66 | // for each unique item in origin array, create a key on result obj 67 | let originNodes: string[] = 68 | resultData.uniDirectionalRelationship[i].originNode; 69 | let uniRelation: string = 70 | resultData.uniDirectionalRelationship[i].relationship; 71 | let dependentNode: string[] = 72 | resultData.uniDirectionalRelationship[i].dependentNode; 73 | if (originNodes.length > 0) { 74 | for (let x = 0; x < originNodes.length; x += 1) { 75 | if (!resultObj[originNodes[x]]) { 76 | resultObj[originNodes[x]] = { 77 | "Uni-Directional": {}, 78 | "Bi-Directional": {}, 79 | Properties: [] 80 | }; 81 | } 82 | resultObj[originNodes[x]]["Uni-Directional"][ 83 | uniRelation 84 | ] = dependentNode; 85 | } 86 | } 87 | } 88 | // BiDirectional 89 | for (let y = 0; y < resultData.biDirectionalRelationship.length; y += 1) { 90 | // Array of all the origin nodes in relationship object 91 | let originNodes = resultData.biDirectionalRelationship[y].originNode; 92 | // Relationship between origin nodes and depenent node 93 | let biRelation = resultData.biDirectionalRelationship[y].relationship; 94 | // Array of depend Nodes 95 | let dependentNode = resultData.biDirectionalRelationship[y].dependentNode; 96 | // for each origin node 97 | for (let z = 0; z < originNodes.length; z += 1) { 98 | // if the node is on the result obj, check if the bi relationship is on the node 99 | resultObj[originNodes[z]]["Bi-Directional"][biRelation] = dependentNode; 100 | } 101 | } 102 | // Properties 103 | for (let q = 0; q < resultData.graphOutline.length; q += 1) { 104 | let nameNode: string = resultData.graphOutline[q].label; 105 | let propsNode: string[] = resultData.graphOutline[q].properties; 106 | 107 | if (!resultObj[nameNode]) { 108 | resultObj[nameNode] = { 109 | "Uni-Directional": {}, 110 | "Bi-Directional": {}, 111 | Properties: [] 112 | }; 113 | } 114 | 115 | if (resultObj[nameNode]) { 116 | resultObj[nameNode].Properties = propsNode; 117 | } 118 | } 119 | return resultObj; 120 | } 121 | /** 122 | * createGraphStructure method is called in constructor and utilizes the boundGetGraphStructure and setUpData methods to populate 123 | * OutlineProvider with correct format for data 124 | */ 125 | createGraphStructure() { 126 | const boundGetGraphStructure = getGraphStructure.bind(this); 127 | 128 | const { dbAddress, username, password } = this.trinityConfig.activeSettings; 129 | 130 | boundGetGraphStructure(dbAddress, username, password).then( 131 | (res: GraphStructure | undefined) => { 132 | if (res !== undefined) { 133 | const resultObject: ResultObject = this.createResultObj(res); 134 | this.data = this.setUpData(resultObject); 135 | this._onDidChangeTreeData.fire(); 136 | } 137 | } 138 | ); 139 | } 140 | /** 141 | * setUpData method accepts resultObj from the createResultObj method and constructs an array of tree tasks that will be used 142 | * to populate the outline view 143 | * @param resultObj 144 | */ 145 | setUpData(resultObj: ResultObject) { 146 | let array: TreeTask[] = []; 147 | 148 | // For each Node in result Object 149 | Object.keys(resultObj).forEach(element => { 150 | let elementArray: TreeTask[] = []; 151 | 152 | // For each Item inside node of Result Objectresult Object 153 | Object.keys(resultObj[element]).forEach(innerEl => { 154 | let innerElArray: TreeTask[] = []; 155 | 156 | // check if person.uni or properties etc is an array 157 | if (innerEl === "Properties") { 158 | resultObj[element].Properties.forEach(innerMostEL => { 159 | innerElArray.push(new TreeTask(innerMostEL)); 160 | }); 161 | } else { 162 | if (innerEl === "Bi-Directional" || innerEl === "Uni-Directional") { 163 | if (resultObj[element][innerEl] !== undefined) { 164 | Object.keys(resultObj[element][innerEl]).forEach(newInnerEl => { 165 | let dependents: TreeTask[] = []; 166 | 167 | resultObj[element][innerEl][newInnerEl].forEach(el => { 168 | dependents.push(new TreeTask(el)); 169 | }); 170 | 171 | innerElArray.push(new TreeTask(newInnerEl, dependents)); 172 | }); 173 | } 174 | } 175 | } 176 | let innerTreeTask = new TreeTask(innerEl, innerElArray); 177 | 178 | elementArray.push(innerTreeTask); 179 | }); 180 | 181 | let elementTreeTask = new TreeTask(element, elementArray); 182 | array.push(elementTreeTask); 183 | }); 184 | console.log(array); 185 | return array; 186 | } 187 | 188 | // Executes command showing outline provider 189 | show() { 190 | vscode.commands.executeCommand("setContext", "trinityOutlineEnabled", true); 191 | } 192 | /** 193 | * VSCode API uses getChildren AND getTreeItem methods to aid in construction of tree task outline view 194 | * @param element 195 | * 196 | */ 197 | getChildren( 198 | element?: TreeTask | undefined 199 | ): vscode.ProviderResult { 200 | if (element === undefined) { 201 | return this.data; 202 | } 203 | return element.children; 204 | } 205 | 206 | getTreeItem(element: TreeTask): vscode.TreeItem | Thenable { 207 | return element; 208 | } 209 | } 210 | class TreeTask extends vscode.TreeItem { 211 | children: TreeTask[] | undefined; 212 | 213 | constructor(label: string, children?: TreeTask[]) { 214 | const collapsed = 215 | children === undefined 216 | ? vscode.TreeItemCollapsibleState.None 217 | : vscode.TreeItemCollapsibleState.Collapsed; 218 | super(label, collapsed); 219 | this.children = children; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/server/neo4j/sampleOutput/movie.cypher: -------------------------------------------------------------------------------- 1 | CREATE (TheMatrix:Movie {title:'The Matrix', released:1999, tagline:'Welcome to the Real World'}) 2 | CREATE (Keanu:Person {name:'Keanu Reeves', born:1964}) 3 | CREATE (Carrie:Person {name:'Carrie-Anne Moss', born:1967}) 4 | CREATE (Laurence:Person {name:'Laurence Fishburne', born:1961}) 5 | CREATE (Hugo:Person {name:'Hugo Weaving', born:1960}) 6 | CREATE (LillyW:Person {name:'Lilly Wachowski', born:1967}) 7 | CREATE (LanaW:Person {name:'Lana Wachowski', born:1965}) 8 | CREATE (JoelS:Person {name:'Joel Silver', born:1952}) 9 | CREATE 10 | (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrix), 11 | (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrix), 12 | (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrix), 13 | (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrix), 14 | (LillyW)-[:DIRECTED]->(TheMatrix), 15 | (LanaW)-[:DIRECTED]->(TheMatrix), 16 | (JoelS)-[:PRODUCED]->(TheMatrix) 17 | 18 | CREATE (Emil:Person {name:"Emil Eifrem", born:1978}) 19 | CREATE (Emil)-[:ACTED_IN {roles:["Emil"]}]->(TheMatrix) 20 | 21 | CREATE (TheMatrixReloaded:Movie {title:'The Matrix Reloaded', released:2003, tagline:'Free your mind'}) 22 | CREATE 23 | (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixReloaded), 24 | (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixReloaded), 25 | (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixReloaded), 26 | (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixReloaded), 27 | (LillyW)-[:DIRECTED]->(TheMatrixReloaded), 28 | (LanaW)-[:DIRECTED]->(TheMatrixReloaded), 29 | (JoelS)-[:PRODUCED]->(TheMatrixReloaded) 30 | 31 | CREATE (TheMatrixRevolutions:Movie {title:'The Matrix Revolutions', released:2003, tagline:'Everything that has a beginning has an end'}) 32 | CREATE 33 | (Keanu)-[:ACTED_IN {roles:['Neo']}]->(TheMatrixRevolutions), 34 | (Carrie)-[:ACTED_IN {roles:['Trinity']}]->(TheMatrixRevolutions), 35 | (Laurence)-[:ACTED_IN {roles:['Morpheus']}]->(TheMatrixRevolutions), 36 | (Hugo)-[:ACTED_IN {roles:['Agent Smith']}]->(TheMatrixRevolutions), 37 | (LillyW)-[:DIRECTED]->(TheMatrixRevolutions), 38 | (LanaW)-[:DIRECTED]->(TheMatrixRevolutions), 39 | (JoelS)-[:PRODUCED]->(TheMatrixRevolutions) 40 | 41 | CREATE (TheDevilsAdvocate:Movie {title:"The Devil's Advocate", released:1997, tagline:'Evil has its winning ways'}) 42 | CREATE (Charlize:Person {name:'Charlize Theron', born:1975}) 43 | CREATE (Al:Person {name:'Al Pacino', born:1940}) 44 | CREATE (Taylor:Person {name:'Taylor Hackford', born:1944}) 45 | CREATE 46 | (Keanu)-[:ACTED_IN {roles:['Kevin Lomax']}]->(TheDevilsAdvocate), 47 | (Charlize)-[:ACTED_IN {roles:['Mary Ann Lomax']}]->(TheDevilsAdvocate), 48 | (Al)-[:ACTED_IN {roles:['John Milton']}]->(TheDevilsAdvocate), 49 | (Taylor)-[:DIRECTED]->(TheDevilsAdvocate) 50 | 51 | CREATE (AFewGoodMen:Movie {title:"A Few Good Men", released:1992, tagline:"In the heart of the nation's capital, in a courthouse of the U.S. government, one man will stop at nothing to keep his honor, and one will stop at nothing to find the truth."}) 52 | CREATE (TomC:Person {name:'Tom Cruise', born:1962}) 53 | CREATE (JackN:Person {name:'Jack Nicholson', born:1937}) 54 | CREATE (DemiM:Person {name:'Demi Moore', born:1962}) 55 | CREATE (KevinB:Person {name:'Kevin Bacon', born:1958}) 56 | CREATE (KieferS:Person {name:'Kiefer Sutherland', born:1966}) 57 | CREATE (NoahW:Person {name:'Noah Wyle', born:1971}) 58 | CREATE (CubaG:Person {name:'Cuba Gooding Jr.', born:1968}) 59 | CREATE (KevinP:Person {name:'Kevin Pollak', born:1957}) 60 | CREATE (JTW:Person {name:'J.T. Walsh', born:1943}) 61 | CREATE (JamesM:Person {name:'James Marshall', born:1967}) 62 | CREATE (ChristopherG:Person {name:'Christopher Guest', born:1948}) 63 | CREATE (RobR:Person {name:'Rob Reiner', born:1947}) 64 | CREATE (AaronS:Person {name:'Aaron Sorkin', born:1961}) 65 | CREATE 66 | (TomC)-[:ACTED_IN {roles:['Lt. Daniel Kaffee']}]->(AFewGoodMen), 67 | (JackN)-[:ACTED_IN {roles:['Col. Nathan R. Jessup']}]->(AFewGoodMen), 68 | (DemiM)-[:ACTED_IN {roles:['Lt. Cdr. JoAnne Galloway']}]->(AFewGoodMen), 69 | (KevinB)-[:ACTED_IN {roles:['Capt. Jack Ross']}]->(AFewGoodMen), 70 | (KieferS)-[:ACTED_IN {roles:['Lt. Jonathan Kendrick']}]->(AFewGoodMen), 71 | (NoahW)-[:ACTED_IN {roles:['Cpl. Jeffrey Barnes']}]->(AFewGoodMen), 72 | (CubaG)-[:ACTED_IN {roles:['Cpl. Carl Hammaker']}]->(AFewGoodMen), 73 | (KevinP)-[:ACTED_IN {roles:['Lt. Sam Weinberg']}]->(AFewGoodMen), 74 | (JTW)-[:ACTED_IN {roles:['Lt. Col. Matthew Andrew Markinson']}]->(AFewGoodMen), 75 | (JamesM)-[:ACTED_IN {roles:['Pfc. Louden Downey']}]->(AFewGoodMen), 76 | (ChristopherG)-[:ACTED_IN {roles:['Dr. Stone']}]->(AFewGoodMen), 77 | (AaronS)-[:ACTED_IN {roles:['Man in Bar']}]->(AFewGoodMen), 78 | (RobR)-[:DIRECTED]->(AFewGoodMen), 79 | (AaronS)-[:WROTE]->(AFewGoodMen) 80 | 81 | CREATE (TopGun:Movie {title:"Top Gun", released:1986, tagline:'I feel the need, the need for speed.'}) 82 | CREATE (KellyM:Person {name:'Kelly McGillis', born:1957}) 83 | CREATE (ValK:Person {name:'Val Kilmer', born:1959}) 84 | CREATE (AnthonyE:Person {name:'Anthony Edwards', born:1962}) 85 | CREATE (TomS:Person {name:'Tom Skerritt', born:1933}) 86 | CREATE (MegR:Person {name:'Meg Ryan', born:1961}) 87 | CREATE (TonyS:Person {name:'Tony Scott', born:1944}) 88 | CREATE (JimC:Person {name:'Jim Cash', born:1941}) 89 | CREATE 90 | (TomC)-[:ACTED_IN {roles:['Maverick']}]->(TopGun), 91 | (KellyM)-[:ACTED_IN {roles:['Charlie']}]->(TopGun), 92 | (ValK)-[:ACTED_IN {roles:['Iceman']}]->(TopGun), 93 | (AnthonyE)-[:ACTED_IN {roles:['Goose']}]->(TopGun), 94 | (TomS)-[:ACTED_IN {roles:['Viper']}]->(TopGun), 95 | (MegR)-[:ACTED_IN {roles:['Carole']}]->(TopGun), 96 | (TonyS)-[:DIRECTED]->(TopGun), 97 | (JimC)-[:WROTE]->(TopGun) 98 | 99 | CREATE (JerryMaguire:Movie {title:'Jerry Maguire', released:2000, tagline:'The rest of his life begins now.'}) 100 | CREATE (ReneeZ:Person {name:'Renee Zellweger', born:1969}) 101 | CREATE (KellyP:Person {name:'Kelly Preston', born:1962}) 102 | CREATE (JerryO:Person {name:"Jerry O'Connell", born:1974}) 103 | CREATE (JayM:Person {name:'Jay Mohr', born:1970}) 104 | CREATE (BonnieH:Person {name:'Bonnie Hunt', born:1961}) 105 | CREATE (ReginaK:Person {name:'Regina King', born:1971}) 106 | CREATE (JonathanL:Person {name:'Jonathan Lipnicki', born:1996}) 107 | CREATE (CameronC:Person {name:'Cameron Crowe', born:1957}) 108 | CREATE 109 | (TomC)-[:ACTED_IN {roles:['Jerry Maguire']}]->(JerryMaguire), 110 | (CubaG)-[:ACTED_IN {roles:['Rod Tidwell']}]->(JerryMaguire), 111 | (ReneeZ)-[:ACTED_IN {roles:['Dorothy Boyd']}]->(JerryMaguire), 112 | (KellyP)-[:ACTED_IN {roles:['Avery Bishop']}]->(JerryMaguire), 113 | (JerryO)-[:ACTED_IN {roles:['Frank Cushman']}]->(JerryMaguire), 114 | (JayM)-[:ACTED_IN {roles:['Bob Sugar']}]->(JerryMaguire), 115 | (BonnieH)-[:ACTED_IN {roles:['Laurel Boyd']}]->(JerryMaguire), 116 | (ReginaK)-[:ACTED_IN {roles:['Marcee Tidwell']}]->(JerryMaguire), 117 | (JonathanL)-[:ACTED_IN {roles:['Ray Boyd']}]->(JerryMaguire), 118 | (CameronC)-[:DIRECTED]->(JerryMaguire), 119 | (CameronC)-[:PRODUCED]->(JerryMaguire), 120 | (CameronC)-[:WROTE]->(JerryMaguire) 121 | 122 | CREATE (StandByMe:Movie {title:"Stand By Me", released:1986, tagline:"For some, it's the last real taste of innocence, and the first real taste of life. But for everyone, it's the time that memories are made of."}) 123 | CREATE (RiverP:Person {name:'River Phoenix', born:1970}) 124 | CREATE (CoreyF:Person {name:'Corey Feldman', born:1971}) 125 | CREATE (WilW:Person {name:'Wil Wheaton', born:1972}) 126 | CREATE (JohnC:Person {name:'John Cusack', born:1966}) 127 | CREATE (MarshallB:Person {name:'Marshall Bell', born:1942}) 128 | CREATE 129 | (WilW)-[:ACTED_IN {roles:['Gordie Lachance']}]->(StandByMe), 130 | (RiverP)-[:ACTED_IN {roles:['Chris Chambers']}]->(StandByMe), 131 | (JerryO)-[:ACTED_IN {roles:['Vern Tessio']}]->(StandByMe), 132 | (CoreyF)-[:ACTED_IN {roles:['Teddy Duchamp']}]->(StandByMe), 133 | (JohnC)-[:ACTED_IN {roles:['Denny Lachance']}]->(StandByMe), 134 | (KieferS)-[:ACTED_IN {roles:['Ace Merrill']}]->(StandByMe), 135 | (MarshallB)-[:ACTED_IN {roles:['Mr. Lachance']}]->(StandByMe), 136 | (RobR)-[:DIRECTED]->(StandByMe) 137 | 138 | CREATE (AsGoodAsItGets:Movie {title:'As Good as It Gets', released:1997, tagline:'A comedy from the heart that goes for the throat.'}) 139 | CREATE (HelenH:Person {name:'Helen Hunt', born:1963}) 140 | CREATE (GregK:Person {name:'Greg Kinnear', born:1963}) 141 | CREATE (JamesB:Person {name:'James L. Brooks', born:1940}) 142 | CREATE 143 | (JackN)-[:ACTED_IN {roles:['Melvin Udall']}]->(AsGoodAsItGets), 144 | (HelenH)-[:ACTED_IN {roles:['Carol Connelly']}]->(AsGoodAsItGets), 145 | (GregK)-[:ACTED_IN {roles:['Simon Bishop']}]->(AsGoodAsItGets), 146 | (CubaG)-[:ACTED_IN {roles:['Frank Sachs']}]->(AsGoodAsItGets), 147 | (JamesB)-[:DIRECTED]->(AsGoodAsItGets) 148 | 149 | CREATE (WhatDreamsMayCome:Movie {title:'What Dreams May Come', released:1998, tagline:'After life there is more. The end is just the beginning.'}) 150 | CREATE (AnnabellaS:Person {name:'Annabella Sciorra', born:1960}) 151 | CREATE (MaxS:Person {name:'Max von Sydow', born:1929}) 152 | CREATE (WernerH:Person {name:'Werner Herzog', born:1942}) 153 | CREATE (Robin:Person {name:'Robin Williams', born:1951}) 154 | CREATE (VincentW:Person {name:'Vincent Ward', born:1956}) 155 | CREATE 156 | (Robin)-[:ACTED_IN {roles:['Chris Nielsen']}]->(WhatDreamsMayCome), 157 | (CubaG)-[:ACTED_IN {roles:['Albert Lewis']}]->(WhatDreamsMayCome), 158 | (AnnabellaS)-[:ACTED_IN {roles:['Annie Collins-Nielsen']}]->(WhatDreamsMayCome), 159 | (MaxS)-[:ACTED_IN {roles:['The Tracker']}]->(WhatDreamsMayCome), 160 | (WernerH)-[:ACTED_IN {roles:['The Face']}]->(WhatDreamsMayCome), 161 | (VincentW)-[:DIRECTED]->(WhatDreamsMayCome) 162 | 163 | CREATE (SnowFallingonCedars:Movie {title:'Snow Falling on Cedars', released:1999, tagline:'First loves last. Forever.'}) 164 | CREATE (EthanH:Person {name:'Ethan Hawke', born:1970}) 165 | CREATE (RickY:Person {name:'Rick Yune', born:1971}) 166 | CREATE (JamesC:Person {name:'James Cromwell', born:1940}) 167 | CREATE (ScottH:Person {name:'Scott Hicks', born:1953}) 168 | CREATE 169 | (EthanH)-[:ACTED_IN {roles:['Ishmael Chambers']}]->(SnowFallingonCedars), 170 | (RickY)-[:ACTED_IN {roles:['Kazuo Miyamoto']}]->(SnowFallingonCedars), 171 | (MaxS)-[:ACTED_IN {roles:['Nels Gudmundsson']}]->(SnowFallingonCedars), 172 | (JamesC)-[:ACTED_IN {roles:['Judge Fielding']}]->(SnowFallingonCedars), 173 | (ScottH)-[:DIRECTED]->(SnowFallingonCedars) 174 | 175 | CREATE (YouveGotMail:Movie {title:"You've Got Mail", released:1998, tagline:'At odds in life... in love on-line.'}) 176 | CREATE (ParkerP:Person {name:'Parker Posey', born:1968}) 177 | CREATE (DaveC:Person {name:'Dave Chappelle', born:1973}) 178 | CREATE (SteveZ:Person {name:'Steve Zahn', born:1967}) 179 | CREATE (TomH:Person {name:'Tom Hanks', born:1956}) 180 | CREATE (NoraE:Person {name:'Nora Ephron', born:1941}) 181 | CREATE 182 | (TomH)-[:ACTED_IN {roles:['Joe Fox']}]->(YouveGotMail), 183 | (MegR)-[:ACTED_IN {roles:['Kathleen Kelly']}]->(YouveGotMail), 184 | (GregK)-[:ACTED_IN {roles:['Frank Navasky']}]->(YouveGotMail), 185 | (ParkerP)-[:ACTED_IN {roles:['Patricia Eden']}]->(YouveGotMail), 186 | (DaveC)-[:ACTED_IN {roles:['Kevin Jackson']}]->(YouveGotMail), 187 | (SteveZ)-[:ACTED_IN {roles:['George Pappas']}]->(YouveGotMail), 188 | (NoraE)-[:DIRECTED]->(YouveGotMail) 189 | 190 | CREATE (SleeplessInSeattle:Movie {title:'Sleepless in Seattle', released:1993, tagline:'What if someone you never met, someone you never saw, someone you never knew was the only someone for you?'}) 191 | CREATE (RitaW:Person {name:'Rita Wilson', born:1956}) 192 | CREATE (BillPull:Person {name:'Bill Pullman', born:1953}) 193 | CREATE (VictorG:Person {name:'Victor Garber', born:1949}) 194 | CREATE (RosieO:Person {name:"Rosie O'Donnell", born:1962}) 195 | CREATE 196 | (TomH)-[:ACTED_IN {roles:['Sam Baldwin']}]->(SleeplessInSeattle), 197 | (MegR)-[:ACTED_IN {roles:['Annie Reed']}]->(SleeplessInSeattle), 198 | (RitaW)-[:ACTED_IN {roles:['Suzy']}]->(SleeplessInSeattle), 199 | (BillPull)-[:ACTED_IN {roles:['Walter']}]->(SleeplessInSeattle), 200 | (VictorG)-[:ACTED_IN {roles:['Greg']}]->(SleeplessInSeattle), 201 | (RosieO)-[:ACTED_IN {roles:['Becky']}]->(SleeplessInSeattle), 202 | (NoraE)-[:DIRECTED]->(SleeplessInSeattle) 203 | 204 | CREATE (JoeVersustheVolcano:Movie {title:'Joe Versus the Volcano', released:1990, tagline:'A story of love, lava and burning desire.'}) 205 | CREATE (JohnS:Person {name:'John Patrick Stanley', born:1950}) 206 | CREATE (Nathan:Person {name:'Nathan Lane', born:1956}) 207 | CREATE 208 | (TomH)-[:ACTED_IN {roles:['Joe Banks']}]->(JoeVersustheVolcano), 209 | (MegR)-[:ACTED_IN {roles:['DeDe', 'Angelica Graynamore', 'Patricia Graynamore']}]->(JoeVersustheVolcano), 210 | (Nathan)-[:ACTED_IN {roles:['Baw']}]->(JoeVersustheVolcano), 211 | (JohnS)-[:DIRECTED]->(JoeVersustheVolcano) 212 | 213 | CREATE (WhenHarryMetSally:Movie {title:'When Harry Met Sally', released:1998, tagline:'Can two friends sleep together and still love each other in the morning?'}) 214 | CREATE (BillyC:Person {name:'Billy Crystal', born:1948}) 215 | CREATE (CarrieF:Person {name:'Carrie Fisher', born:1956}) 216 | CREATE (BrunoK:Person {name:'Bruno Kirby', born:1949}) 217 | CREATE 218 | (BillyC)-[:ACTED_IN {roles:['Harry Burns']}]->(WhenHarryMetSally), 219 | (MegR)-[:ACTED_IN {roles:['Sally Albright']}]->(WhenHarryMetSally), 220 | (CarrieF)-[:ACTED_IN {roles:['Marie']}]->(WhenHarryMetSally), 221 | (BrunoK)-[:ACTED_IN {roles:['Jess']}]->(WhenHarryMetSally), 222 | (RobR)-[:DIRECTED]->(WhenHarryMetSally), 223 | (RobR)-[:PRODUCED]->(WhenHarryMetSally), 224 | (NoraE)-[:PRODUCED]->(WhenHarryMetSally), 225 | (NoraE)-[:WROTE]->(WhenHarryMetSally) 226 | 227 | CREATE (ThatThingYouDo:Movie {title:'That Thing You Do', released:1996, tagline:'In every life there comes a time when that thing you dream becomes that thing you do'}) 228 | CREATE (LivT:Person {name:'Liv Tyler', born:1977}) 229 | CREATE 230 | (TomH)-[:ACTED_IN {roles:['Mr. White']}]->(ThatThingYouDo), 231 | (LivT)-[:ACTED_IN {roles:['Faye Dolan']}]->(ThatThingYouDo), 232 | (Charlize)-[:ACTED_IN {roles:['Tina']}]->(ThatThingYouDo), 233 | (TomH)-[:DIRECTED]->(ThatThingYouDo) 234 | 235 | CREATE (TheReplacements:Movie {title:'The Replacements', released:2000, tagline:'Pain heals, Chicks dig scars... Glory lasts forever'}) 236 | CREATE (Brooke:Person {name:'Brooke Langton', born:1970}) 237 | CREATE (Gene:Person {name:'Gene Hackman', born:1930}) 238 | CREATE (Orlando:Person {name:'Orlando Jones', born:1968}) 239 | CREATE (Howard:Person {name:'Howard Deutch', born:1950}) 240 | CREATE 241 | (Keanu)-[:ACTED_IN {roles:['Shane Falco']}]->(TheReplacements), 242 | (Brooke)-[:ACTED_IN {roles:['Annabelle Farrell']}]->(TheReplacements), 243 | (Gene)-[:ACTED_IN {roles:['Jimmy McGinty']}]->(TheReplacements), 244 | (Orlando)-[:ACTED_IN {roles:['Clifford Franklin']}]->(TheReplacements), 245 | (Howard)-[:DIRECTED]->(TheReplacements) 246 | 247 | CREATE (RescueDawn:Movie {title:'RescueDawn', released:2006, tagline:"Based on the extraordinary true story of one man's fight for freedom"}) 248 | CREATE (ChristianB:Person {name:'Christian Bale', born:1974}) 249 | CREATE (ZachG:Person {name:'Zach Grenier', born:1954}) 250 | CREATE 251 | (MarshallB)-[:ACTED_IN {roles:['Admiral']}]->(RescueDawn), 252 | (ChristianB)-[:ACTED_IN {roles:['Dieter Dengler']}]->(RescueDawn), 253 | (ZachG)-[:ACTED_IN {roles:['Squad Leader']}]->(RescueDawn), 254 | (SteveZ)-[:ACTED_IN {roles:['Duane']}]->(RescueDawn), 255 | (WernerH)-[:DIRECTED]->(RescueDawn) 256 | 257 | CREATE (TheBirdcage:Movie {title:'The Birdcage', released:1996, tagline:'Come as you are'}) 258 | CREATE (MikeN:Person {name:'Mike Nichols', born:1931}) 259 | CREATE 260 | (Robin)-[:ACTED_IN {roles:['Armand Goldman']}]->(TheBirdcage), 261 | (Nathan)-[:ACTED_IN {roles:['Albert Goldman']}]->(TheBirdcage), 262 | (Gene)-[:ACTED_IN {roles:['Sen. Kevin Keeley']}]->(TheBirdcage), 263 | (MikeN)-[:DIRECTED]->(TheBirdcage) 264 | 265 | CREATE (Unforgiven:Movie {title:'Unforgiven', released:1992, tagline:"It's a hell of a thing, killing a man"}) 266 | CREATE (RichardH:Person {name:'Richard Harris', born:1930}) 267 | CREATE (ClintE:Person {name:'Clint Eastwood', born:1930}) 268 | CREATE 269 | (RichardH)-[:ACTED_IN {roles:['English Bob']}]->(Unforgiven), 270 | (ClintE)-[:ACTED_IN {roles:['Bill Munny']}]->(Unforgiven), 271 | (Gene)-[:ACTED_IN {roles:['Little Bill Daggett']}]->(Unforgiven), 272 | (ClintE)-[:DIRECTED]->(Unforgiven) 273 | 274 | CREATE (JohnnyMnemonic:Movie {title:'Johnny Mnemonic', released:1995, tagline:'The hottest data on earth. In the coolest head in town'}) 275 | CREATE (Takeshi:Person {name:'Takeshi Kitano', born:1947}) 276 | CREATE (Dina:Person {name:'Dina Meyer', born:1968}) 277 | CREATE (IceT:Person {name:'Ice-T', born:1958}) 278 | CREATE (RobertL:Person {name:'Robert Longo', born:1953}) 279 | CREATE 280 | (Keanu)-[:ACTED_IN {roles:['Johnny Mnemonic']}]->(JohnnyMnemonic), 281 | (Takeshi)-[:ACTED_IN {roles:['Takahashi']}]->(JohnnyMnemonic), 282 | (Dina)-[:ACTED_IN {roles:['Jane']}]->(JohnnyMnemonic), 283 | (IceT)-[:ACTED_IN {roles:['J-Bone']}]->(JohnnyMnemonic), 284 | (RobertL)-[:DIRECTED]->(JohnnyMnemonic) 285 | 286 | CREATE (CloudAtlas:Movie {title:'Cloud Atlas', released:2012, tagline:'Everything is connected'}) 287 | CREATE (HalleB:Person {name:'Halle Berry', born:1966}) 288 | CREATE (JimB:Person {name:'Jim Broadbent', born:1949}) 289 | CREATE (TomT:Person {name:'Tom Tykwer', born:1965}) 290 | CREATE (DavidMitchell:Person {name:'David Mitchell', born:1969}) 291 | CREATE (StefanArndt:Person {name:'Stefan Arndt', born:1961}) 292 | CREATE 293 | (TomH)-[:ACTED_IN {roles:['Zachry', 'Dr. Henry Goose', 'Isaac Sachs', 'Dermot Hoggins']}]->(CloudAtlas), 294 | (Hugo)-[:ACTED_IN {roles:['Bill Smoke', 'Haskell Moore', 'Tadeusz Kesselring', 'Nurse Noakes', 'Boardman Mephi', 'Old Georgie']}]->(CloudAtlas), 295 | (HalleB)-[:ACTED_IN {roles:['Luisa Rey', 'Jocasta Ayrs', 'Ovid', 'Meronym']}]->(CloudAtlas), 296 | (JimB)-[:ACTED_IN {roles:['Vyvyan Ayrs', 'Captain Molyneux', 'Timothy Cavendish']}]->(CloudAtlas), 297 | (TomT)-[:DIRECTED]->(CloudAtlas), 298 | (LillyW)-[:DIRECTED]->(CloudAtlas), 299 | (LanaW)-[:DIRECTED]->(CloudAtlas), 300 | (DavidMitchell)-[:WROTE]->(CloudAtlas), 301 | (StefanArndt)-[:PRODUCED]->(CloudAtlas) 302 | 303 | CREATE (TheDaVinciCode:Movie {title:'The Da Vinci Code', released:2006, tagline:'Break The Codes'}) 304 | CREATE (IanM:Person {name:'Ian McKellen', born:1939}) 305 | CREATE (AudreyT:Person {name:'Audrey Tautou', born:1976}) 306 | CREATE (PaulB:Person {name:'Paul Bettany', born:1971}) 307 | CREATE (RonH:Person {name:'Ron Howard', born:1954}) 308 | CREATE 309 | (TomH)-[:ACTED_IN {roles:['Dr. Robert Langdon']}]->(TheDaVinciCode), 310 | (IanM)-[:ACTED_IN {roles:['Sir Leight Teabing']}]->(TheDaVinciCode), 311 | (AudreyT)-[:ACTED_IN {roles:['Sophie Neveu']}]->(TheDaVinciCode), 312 | (PaulB)-[:ACTED_IN {roles:['Silas']}]->(TheDaVinciCode), 313 | (RonH)-[:DIRECTED]->(TheDaVinciCode) 314 | 315 | CREATE (VforVendetta:Movie {title:'V for Vendetta', released:2006, tagline:'Freedom! Forever!'}) 316 | CREATE (NatalieP:Person {name:'Natalie Portman', born:1981}) 317 | CREATE (StephenR:Person {name:'Stephen Rea', born:1946}) 318 | CREATE (JohnH:Person {name:'John Hurt', born:1940}) 319 | CREATE (BenM:Person {name: 'Ben Miles', born:1967}) 320 | CREATE 321 | (Hugo)-[:ACTED_IN {roles:['V']}]->(VforVendetta), 322 | (NatalieP)-[:ACTED_IN {roles:['Evey Hammond']}]->(VforVendetta), 323 | (StephenR)-[:ACTED_IN {roles:['Eric Finch']}]->(VforVendetta), 324 | (JohnH)-[:ACTED_IN {roles:['High Chancellor Adam Sutler']}]->(VforVendetta), 325 | (BenM)-[:ACTED_IN {roles:['Dascomb']}]->(VforVendetta), 326 | (JamesM)-[:DIRECTED]->(VforVendetta), 327 | (LillyW)-[:PRODUCED]->(VforVendetta), 328 | (LanaW)-[:PRODUCED]->(VforVendetta), 329 | (JoelS)-[:PRODUCED]->(VforVendetta), 330 | (LillyW)-[:WROTE]->(VforVendetta), 331 | (LanaW)-[:WROTE]->(VforVendetta) 332 | 333 | CREATE (SpeedRacer:Movie {title:'Speed Racer', released:2008, tagline:'Speed has no limits'}) 334 | CREATE (EmileH:Person {name:'Emile Hirsch', born:1985}) 335 | CREATE (JohnG:Person {name:'John Goodman', born:1960}) 336 | CREATE (SusanS:Person {name:'Susan Sarandon', born:1946}) 337 | CREATE (MatthewF:Person {name:'Matthew Fox', born:1966}) 338 | CREATE (ChristinaR:Person {name:'Christina Ricci', born:1980}) 339 | CREATE (Rain:Person {name:'Rain', born:1982}) 340 | CREATE 341 | (EmileH)-[:ACTED_IN {roles:['Speed Racer']}]->(SpeedRacer), 342 | (JohnG)-[:ACTED_IN {roles:['Pops']}]->(SpeedRacer), 343 | (SusanS)-[:ACTED_IN {roles:['Mom']}]->(SpeedRacer), 344 | (MatthewF)-[:ACTED_IN {roles:['Racer X']}]->(SpeedRacer), 345 | (ChristinaR)-[:ACTED_IN {roles:['Trixie']}]->(SpeedRacer), 346 | (Rain)-[:ACTED_IN {roles:['Taejo Togokahn']}]->(SpeedRacer), 347 | (BenM)-[:ACTED_IN {roles:['Cass Jones']}]->(SpeedRacer), 348 | (LillyW)-[:DIRECTED]->(SpeedRacer), 349 | (LanaW)-[:DIRECTED]->(SpeedRacer), 350 | (LillyW)-[:WROTE]->(SpeedRacer), 351 | (LanaW)-[:WROTE]->(SpeedRacer), 352 | (JoelS)-[:PRODUCED]->(SpeedRacer) 353 | 354 | CREATE (NinjaAssassin:Movie {title:'Ninja Assassin', released:2009, tagline:'Prepare to enter a secret world of assassins'}) 355 | CREATE (NaomieH:Person {name:'Naomie Harris'}) 356 | CREATE 357 | (Rain)-[:ACTED_IN {roles:['Raizo']}]->(NinjaAssassin), 358 | (NaomieH)-[:ACTED_IN {roles:['Mika Coretti']}]->(NinjaAssassin), 359 | (RickY)-[:ACTED_IN {roles:['Takeshi']}]->(NinjaAssassin), 360 | (BenM)-[:ACTED_IN {roles:['Ryan Maslow']}]->(NinjaAssassin), 361 | (JamesM)-[:DIRECTED]->(NinjaAssassin), 362 | (LillyW)-[:PRODUCED]->(NinjaAssassin), 363 | (LanaW)-[:PRODUCED]->(NinjaAssassin), 364 | (JoelS)-[:PRODUCED]->(NinjaAssassin) 365 | 366 | CREATE (TheGreenMile:Movie {title:'The Green Mile', released:1999, tagline:"Walk a mile you'll never forget."}) 367 | CREATE (MichaelD:Person {name:'Michael Clarke Duncan', born:1957}) 368 | CREATE (DavidM:Person {name:'David Morse', born:1953}) 369 | CREATE (SamR:Person {name:'Sam Rockwell', born:1968}) 370 | CREATE (GaryS:Person {name:'Gary Sinise', born:1955}) 371 | CREATE (PatriciaC:Person {name:'Patricia Clarkson', born:1959}) 372 | CREATE (FrankD:Person {name:'Frank Darabont', born:1959}) 373 | CREATE 374 | (TomH)-[:ACTED_IN {roles:['Paul Edgecomb']}]->(TheGreenMile), 375 | (MichaelD)-[:ACTED_IN {roles:['John Coffey']}]->(TheGreenMile), 376 | (DavidM)-[:ACTED_IN {roles:['Brutus "Brutal" Howell']}]->(TheGreenMile), 377 | (BonnieH)-[:ACTED_IN {roles:['Jan Edgecomb']}]->(TheGreenMile), 378 | (JamesC)-[:ACTED_IN {roles:['Warden Hal Moores']}]->(TheGreenMile), 379 | (SamR)-[:ACTED_IN {roles:['"Wild Bill" Wharton']}]->(TheGreenMile), 380 | (GaryS)-[:ACTED_IN {roles:['Burt Hammersmith']}]->(TheGreenMile), 381 | (PatriciaC)-[:ACTED_IN {roles:['Melinda Moores']}]->(TheGreenMile), 382 | (FrankD)-[:DIRECTED]->(TheGreenMile) 383 | 384 | CREATE (FrostNixon:Movie {title:'Frost/Nixon', released:2008, tagline:'400 million people were waiting for the truth.'}) 385 | CREATE (FrankL:Person {name:'Frank Langella', born:1938}) 386 | CREATE (MichaelS:Person {name:'Michael Sheen', born:1969}) 387 | CREATE (OliverP:Person {name:'Oliver Platt', born:1960}) 388 | CREATE 389 | (FrankL)-[:ACTED_IN {roles:['Richard Nixon']}]->(FrostNixon), 390 | (MichaelS)-[:ACTED_IN {roles:['David Frost']}]->(FrostNixon), 391 | (KevinB)-[:ACTED_IN {roles:['Jack Brennan']}]->(FrostNixon), 392 | (OliverP)-[:ACTED_IN {roles:['Bob Zelnick']}]->(FrostNixon), 393 | (SamR)-[:ACTED_IN {roles:['James Reston, Jr.']}]->(FrostNixon), 394 | (RonH)-[:DIRECTED]->(FrostNixon) 395 | 396 | CREATE (Hoffa:Movie {title:'Hoffa', released:1992, tagline:"He didn't want law. He wanted justice."}) 397 | CREATE (DannyD:Person {name:'Danny DeVito', born:1944}) 398 | CREATE (JohnR:Person {name:'John C. Reilly', born:1965}) 399 | CREATE 400 | (JackN)-[:ACTED_IN {roles:['Hoffa']}]->(Hoffa), 401 | (DannyD)-[:ACTED_IN {roles:['Robert "Bobby" Ciaro']}]->(Hoffa), 402 | (JTW)-[:ACTED_IN {roles:['Frank Fitzsimmons']}]->(Hoffa), 403 | (JohnR)-[:ACTED_IN {roles:['Peter "Pete" Connelly']}]->(Hoffa), 404 | (DannyD)-[:DIRECTED]->(Hoffa) 405 | 406 | CREATE (Apollo13:Movie {title:'Apollo 13', released:1995, tagline:'Houston, we have a problem.'}) 407 | CREATE (EdH:Person {name:'Ed Harris', born:1950}) 408 | CREATE (BillPax:Person {name:'Bill Paxton', born:1955}) 409 | CREATE 410 | (TomH)-[:ACTED_IN {roles:['Jim Lovell']}]->(Apollo13), 411 | (KevinB)-[:ACTED_IN {roles:['Jack Swigert']}]->(Apollo13), 412 | (EdH)-[:ACTED_IN {roles:['Gene Kranz']}]->(Apollo13), 413 | (BillPax)-[:ACTED_IN {roles:['Fred Haise']}]->(Apollo13), 414 | (GaryS)-[:ACTED_IN {roles:['Ken Mattingly']}]->(Apollo13), 415 | (RonH)-[:DIRECTED]->(Apollo13) 416 | 417 | CREATE (Twister:Movie {title:'Twister', released:1996, tagline:"Don't Breathe. Don't Look Back."}) 418 | CREATE (PhilipH:Person {name:'Philip Seymour Hoffman', born:1967}) 419 | CREATE (JanB:Person {name:'Jan de Bont', born:1943}) 420 | CREATE 421 | (BillPax)-[:ACTED_IN {roles:['Bill Harding']}]->(Twister), 422 | (HelenH)-[:ACTED_IN {roles:['Dr. Jo Harding']}]->(Twister), 423 | (ZachG)-[:ACTED_IN {roles:['Eddie']}]->(Twister), 424 | (PhilipH)-[:ACTED_IN {roles:['Dustin "Dusty" Davis']}]->(Twister), 425 | (JanB)-[:DIRECTED]->(Twister) 426 | 427 | CREATE (CastAway:Movie {title:'Cast Away', released:2000, tagline:'At the edge of the world, his journey begins.'}) 428 | CREATE (RobertZ:Person {name:'Robert Zemeckis', born:1951}) 429 | CREATE 430 | (TomH)-[:ACTED_IN {roles:['Chuck Noland']}]->(CastAway), 431 | (HelenH)-[:ACTED_IN {roles:['Kelly Frears']}]->(CastAway), 432 | (RobertZ)-[:DIRECTED]->(CastAway) 433 | 434 | CREATE (OneFlewOvertheCuckoosNest:Movie {title:"One Flew Over the Cuckoo's Nest", released:1975, tagline:"If he's crazy, what does that make you?"}) 435 | CREATE (MilosF:Person {name:'Milos Forman', born:1932}) 436 | CREATE 437 | (JackN)-[:ACTED_IN {roles:['Randle McMurphy']}]->(OneFlewOvertheCuckoosNest), 438 | (DannyD)-[:ACTED_IN {roles:['Martini']}]->(OneFlewOvertheCuckoosNest), 439 | (MilosF)-[:DIRECTED]->(OneFlewOvertheCuckoosNest) 440 | 441 | CREATE (SomethingsGottaGive:Movie {title:"Something's Gotta Give", released:2003}) 442 | CREATE (DianeK:Person {name:'Diane Keaton', born:1946}) 443 | CREATE (NancyM:Person {name:'Nancy Meyers', born:1949}) 444 | CREATE 445 | (JackN)-[:ACTED_IN {roles:['Harry Sanborn']}]->(SomethingsGottaGive), 446 | (DianeK)-[:ACTED_IN {roles:['Erica Barry']}]->(SomethingsGottaGive), 447 | (Keanu)-[:ACTED_IN {roles:['Julian Mercer']}]->(SomethingsGottaGive), 448 | (NancyM)-[:DIRECTED]->(SomethingsGottaGive), 449 | (NancyM)-[:PRODUCED]->(SomethingsGottaGive), 450 | (NancyM)-[:WROTE]->(SomethingsGottaGive) 451 | 452 | CREATE (BicentennialMan:Movie {title:'Bicentennial Man', released:1999, tagline:"One robot's 200 year journey to become an ordinary man."}) 453 | CREATE (ChrisC:Person {name:'Chris Columbus', born:1958}) 454 | CREATE 455 | (Robin)-[:ACTED_IN {roles:['Andrew Marin']}]->(BicentennialMan), 456 | (OliverP)-[:ACTED_IN {roles:['Rupert Burns']}]->(BicentennialMan), 457 | (ChrisC)-[:DIRECTED]->(BicentennialMan) 458 | 459 | CREATE (CharlieWilsonsWar:Movie {title:"Charlie Wilson's War", released:2007, tagline:"A stiff drink. A little mascara. A lot of nerve. Who said they couldn't bring down the Soviet empire."}) 460 | CREATE (JuliaR:Person {name:'Julia Roberts', born:1967}) 461 | CREATE 462 | (TomH)-[:ACTED_IN {roles:['Rep. Charlie Wilson']}]->(CharlieWilsonsWar), 463 | (JuliaR)-[:ACTED_IN {roles:['Joanne Herring']}]->(CharlieWilsonsWar), 464 | (PhilipH)-[:ACTED_IN {roles:['Gust Avrakotos']}]->(CharlieWilsonsWar), 465 | (MikeN)-[:DIRECTED]->(CharlieWilsonsWar) 466 | 467 | CREATE (ThePolarExpress:Movie {title:'The Polar Express', released:2004, tagline:'This Holiday Season… Believe'}) 468 | CREATE 469 | (TomH)-[:ACTED_IN {roles:['Hero Boy', 'Father', 'Conductor', 'Hobo', 'Scrooge', 'Santa Claus']}]->(ThePolarExpress), 470 | (RobertZ)-[:DIRECTED]->(ThePolarExpress) 471 | 472 | CREATE (ALeagueofTheirOwn:Movie {title:'A League of Their Own', released:1992, tagline:'Once in a lifetime you get a chance to do something different.'}) 473 | CREATE (Madonna:Person {name:'Madonna', born:1954}) 474 | CREATE (GeenaD:Person {name:'Geena Davis', born:1956}) 475 | CREATE (LoriP:Person {name:'Lori Petty', born:1963}) 476 | CREATE (PennyM:Person {name:'Penny Marshall', born:1943}) 477 | CREATE 478 | (TomH)-[:ACTED_IN {roles:['Jimmy Dugan']}]->(ALeagueofTheirOwn), 479 | (GeenaD)-[:ACTED_IN {roles:['Dottie Hinson']}]->(ALeagueofTheirOwn), 480 | (LoriP)-[:ACTED_IN {roles:['Kit Keller']}]->(ALeagueofTheirOwn), 481 | (RosieO)-[:ACTED_IN {roles:['Doris Murphy']}]->(ALeagueofTheirOwn), 482 | (Madonna)-[:ACTED_IN {roles:['"All the Way" Mae Mordabito']}]->(ALeagueofTheirOwn), 483 | (BillPax)-[:ACTED_IN {roles:['Bob Hinson']}]->(ALeagueofTheirOwn), 484 | (PennyM)-[:DIRECTED]->(ALeagueofTheirOwn) 485 | 486 | CREATE (PaulBlythe:Person {name:'Paul Blythe'}) 487 | CREATE (AngelaScope:Person {name:'Angela Scope'}) 488 | CREATE (JessicaThompson:Person {name:'Jessica Thompson'}) 489 | CREATE (JamesThompson:Person {name:'James Thompson'}) 490 | 491 | CREATE 492 | (JamesThompson)-[:FOLLOWS]->(JessicaThompson), 493 | (AngelaScope)-[:FOLLOWS]->(JessicaThompson), 494 | (PaulBlythe)-[:FOLLOWS]->(AngelaScope) 495 | 496 | CREATE 497 | (JessicaThompson)-[:REVIEWED {summary:'An amazing journey', rating:95}]->(CloudAtlas), 498 | (JessicaThompson)-[:REVIEWED {summary:'Silly, but fun', rating:65}]->(TheReplacements), 499 | (JamesThompson)-[:REVIEWED {summary:'The coolest football movie ever', rating:100}]->(TheReplacements), 500 | (AngelaScope)-[:REVIEWED {summary:'Pretty funny at times', rating:62}]->(TheReplacements), 501 | (JessicaThompson)-[:REVIEWED {summary:'Dark, but compelling', rating:85}]->(Unforgiven), 502 | (JessicaThompson)-[:REVIEWED {summary:"Slapstick redeemed only by the Robin Williams and Gene Hackman's stellar performances", rating:45}]->(TheBirdcage), 503 | (JessicaThompson)-[:REVIEWED {summary:'A solid romp', rating:68}]->(TheDaVinciCode), 504 | (JamesThompson)-[:REVIEWED {summary:'Fun, but a little far fetched', rating:65}]->(TheDaVinciCode), 505 | (JessicaThompson)-[:REVIEWED {summary:'You had me at Jerry', rating:92}]->(JerryMaguire) 506 | 507 | WITH TomH as a 508 | MATCH (a)-[:ACTED_IN]->(m)<-[:DIRECTED]-(d) RETURN a,m,d LIMIT 10; --------------------------------------------------------------------------------