UNPKG

@neo4j-cypher/language-support

Version:
234 lines (190 loc) 6.84 kB
import { CompletionItemKind } from 'vscode-languageserver-types'; import { testCompletions } from './completionAssertionHelpers'; describe('unscoped variable completions', () => { test('correctly completes variables in WHERE clause that have been defined in a simple match', () => { const basequery = (varName: string) => `MATCH (${varName}) WHERE `; const varNames = ['n', 'person', 'MATCH']; varNames.forEach((varName) => { testCompletions({ query: basequery(varName), expected: [{ label: varName, kind: CompletionItemKind.Variable }], }); }); }); test('correctly completes variables from pattern in match', () => { const query = 'MATCH p=(n:Person {n: 23})-[r:KNOWS {since: 213, g: rand()}]->(m:Person) WHERE '; testCompletions({ query, expected: [ { label: 'p', kind: CompletionItemKind.Variable }, { label: 'n', kind: CompletionItemKind.Variable }, { label: 'r', kind: CompletionItemKind.Variable }, ], }); }); test('suggests variable in WITH', () => { const query = 'MATCH (n:Person) WITH '; testCompletions({ query, expected: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('suggests both variables after renaming variable', () => { const query = 'MATCH (n:Person) WITH n as m RETURN '; testCompletions({ query, expected: [ { label: 'n', kind: CompletionItemKind.Variable }, { label: 'm', kind: CompletionItemKind.Variable }, ], }); }); test('does not suggest variable when renaming variable', () => { const query = 'MATCH (n:Person) WITH n as '; testCompletions({ query, excluded: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('does not suggest variables when unwinding ', () => { const query = 'MATCH (n:Person) UNWIND [] as '; testCompletions({ query, excluded: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('suggests variable in expression', () => { const query = 'WITH 1 as n RETURN db.function('; testCompletions({ query, expected: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('does not complete unstarted variables that are used but not defined', () => { const query = 'MATCH (m:Person) WHERE n.name = "foo" RETURN n.name, n.age, '; testCompletions({ query, expected: [{ label: 'm', kind: CompletionItemKind.Variable }], excluded: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('does not complete variables that are used but not defined', () => { const query = 'MATCH (abc:Person) WHERE movie.name = "foo" RETURN movie.name, movie.age, m'; testCompletions({ query, expected: [{ label: 'abc', kind: CompletionItemKind.Variable }], excluded: [{ label: 'movie', kind: CompletionItemKind.Variable }], }); }); test('suggests variable for set', () => { const query = 'MATCH (n:Person) SET '; testCompletions({ query, expected: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('suggests variable for remove', () => { const query = 'MATCH (n:Person) REMOVE '; testCompletions({ query, expected: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('suggests variables for index hint rule', () => { const query = 'match (n) USING BTREE INDEX '; testCompletions({ query, expected: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('does not suggest existing variables in clauses that create variables', () => { const cases = ['FOREACH (', 'LOAD CSV WITH HEADERS FROM 2 AS ']; const base = 'WITH 1 as a '; cases.forEach((c) => { testCompletions({ query: base + c, excluded: [{ label: 'a', kind: CompletionItemKind.Variable }], }); }); }); test('does not suggest existing variables in expressions that create variables', () => { const cases = ['reduce(', 'all(', 'any(', 'none(', 'single(']; const base = 'WITH 1 as a RETURN '; cases.forEach((c) => { testCompletions({ query: base + c, excluded: [{ label: 'a', kind: CompletionItemKind.Variable }], }); }); }); test('should not suggest variable when creating on in procedureResultItem', () => { const query = 'WITH 1 as n CALL apoc.super.thing() YIELD header as '; testCompletions({ query, excluded: [{ label: 'n', kind: CompletionItemKind.Variable }], }); }); test('should not take self into account for suggestions', () => { const query = 'RETURN variable'; testCompletions({ query, excluded: [{ label: 'variable', kind: CompletionItemKind.Variable }], }); }); test("variables don't get suggested when working on constraints", () => { // dropping/ creating constraints is a top level command/statement so // we can't declare any variables to test against // this test is just for sanity checking that we don't suggest any variables const nodeConstraint = 'DROP CONSTRAINT ON ('; const relConstraint = 'DROP CONSTRAINT ON ()-['; const propertyList = 'DROP CONSTRAINT ON (:Person) ASSERT EXISTS '; [nodeConstraint, relConstraint, propertyList].forEach((query) => { testCompletions({ query, excluded: [{ kind: CompletionItemKind.Variable }], }); }); }); test('variables in map projections', () => { const query = `MATCH (movie:Movie) RETURN movie { . `; testCompletions({ query, excluded: [{ label: 'movie', kind: CompletionItemKind.Variable }], }); }); test('completes path variable', () => { const query = `MATCH path=() RETURN `; testCompletions({ query, expected: [{ label: 'path', kind: CompletionItemKind.Variable }], }); }); test('completes variable from list comprehension', () => { const query = `RETURN [var IN list WHERE v`; testCompletions({ query, expected: [{ label: 'var', kind: CompletionItemKind.Variable }], }); }); test('handle binding variables in subqueryInTransactionsReportParameters properly', () => { const query = `CALL { WITH 1 as a } IN TRANSACTIONS REPORT STATUS AS `; testCompletions({ query, excluded: [{ label: 'a', kind: CompletionItemKind.Variable }], }); }); test('does not suggest variables from other statements', () => { const query = 'MATCH (n:Person) RETURN n; MATCH (x:Dog) RETURN '; testCompletions({ query, excluded: [{ label: 'n', kind: CompletionItemKind.Variable }], expected: [{ label: 'x', kind: CompletionItemKind.Variable }], }); }); });