@neo4j-cypher/language-support
Version:
Cypher language support
234 lines (190 loc) • 6.84 kB
text/typescript
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 }],
});
});
});