From 188729344bb6aecb92c49a7ce5a6771c7ae5e2b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Cord=C3=B3n?= Date: Mon, 16 Oct 2023 23:44:05 +0200 Subject: [PATCH] Fixes warnings on non declared labels --- .../syntaxValidation/syntaxValidation.ts | 3 +- .../language-support/src/parserWrapper.ts | 18 +- .../syntacticValidation.test.ts | 179 +++++++++++++++++- 3 files changed, 180 insertions(+), 20 deletions(-) diff --git a/packages/language-support/src/highlighting/syntaxValidation/syntaxValidation.ts b/packages/language-support/src/highlighting/syntaxValidation/syntaxValidation.ts index 9f657c559..faba6479d 100644 --- a/packages/language-support/src/highlighting/syntaxValidation/syntaxValidation.ts +++ b/packages/language-support/src/highlighting/syntaxValidation/syntaxValidation.ts @@ -63,8 +63,9 @@ function warnOnUndeclaredLabels( if (dbSchema.labels && dbSchema.relationshipTypes) { const dbLabels = new Set(dbSchema.labels); const dbRelationshipTypes = new Set(dbSchema.relationshipTypes); + const labelsAndRelTypes = parsingResult.collectedLabelOrRelTypes; - parsingResult.collectedLabelOrRelTypes.forEach((labelOrRelType) => { + labelsAndRelTypes.forEach((labelOrRelType) => { const warning = detectNonDeclaredLabel( labelOrRelType, dbLabels, diff --git a/packages/language-support/src/parserWrapper.ts b/packages/language-support/src/parserWrapper.ts index 368e0f5fb..e5634f27e 100644 --- a/packages/language-support/src/parserWrapper.ts +++ b/packages/language-support/src/parserWrapper.ts @@ -10,12 +10,9 @@ import CypherLexer from './generated-parser/CypherLexer'; import CypherParser, { ClauseContext, - CreateClauseContext, - ExpressionContext, LabelNameContext, LabelNameIsContext, LabelOrRelTypeContext, - MergeClauseContext, StatementsContext, VariableContext, } from './generated-parser/CypherParser'; @@ -53,15 +50,14 @@ function getLabelType(ctx: ParserRuleContext): LabelType { } function couldCreateNewLabel(ctx: ParserRuleContext): boolean { - const parent = findParent( - ctx, - (ctx) => ctx instanceof ClauseContext || ctx instanceof ExpressionContext, - ); + const parent = findParent(ctx, (ctx) => ctx instanceof ClauseContext); - return ( - parent instanceof CreateClauseContext || - parent instanceof MergeClauseContext - ); + if (parent instanceof ClauseContext) { + const clause = parent; + return isDefined(clause.mergeClause()) || isDefined(clause.createClause()); + } else { + return false; + } } export type LabelOrRelType = { diff --git a/packages/language-support/src/tests/highlighting/syntaxValidation/syntacticValidation.test.ts b/packages/language-support/src/tests/highlighting/syntaxValidation/syntacticValidation.test.ts index 596ca4267..d05424cf7 100644 --- a/packages/language-support/src/tests/highlighting/syntaxValidation/syntacticValidation.test.ts +++ b/packages/language-support/src/tests/highlighting/syntaxValidation/syntacticValidation.test.ts @@ -188,29 +188,122 @@ describe('Syntactic validation spec', () => { ]); }); - test('Syntax validation warns on missing relationship type when database can be contacted', () => { - const query = `MATCH (n)-[r:Rel3]->(m) RETURN n`; + test('Syntax validation warns on missing rel type when database can be contacted', () => { + const query = `MATCH (n)-[:Rel]->(m) RETURN n`; expect( getDiagnosticsForQuery({ query, - dbSchema: { labels: ['Rel3'], relationshipTypes: ['Rel1', 'Rel2'] }, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, }), ).toEqual([ { + message: + "Relationship type Rel is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application", offsets: { - end: 17, - start: 13, + end: 15, + start: 12, }, + range: { + end: { + character: 15, + line: 0, + }, + start: { + character: 12, + line: 0, + }, + }, + severity: 2, + }, + ]); + }); + + test('Syntax validation warns on missing label in a WHERE node predicate', () => { + const query = `MATCH (n WHERE n IS Person) RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([ + { message: - "Relationship type Rel3 is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application", + "Label Person is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application", + offsets: { + end: 26, + start: 20, + }, range: { end: { - character: 17, + character: 26, line: 0, }, start: { - character: 13, + character: 20, + line: 0, + }, + }, + severity: 2, + }, + ]); + }); + + test('Syntax validation warns on missing label in a WHERE clause if no labels or rel types match it', () => { + const query = `MATCH (n) WHERE n IS Person RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Cow'] }, + }), + ).toEqual([ + { + message: + "Label or relationship type Person is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application", + offsets: { + end: 27, + start: 21, + }, + range: { + end: { + character: 27, + line: 0, + }, + start: { + character: 21, + line: 0, + }, + }, + severity: 2, + }, + ]); + }); + + test('Syntax validation warns on missing rel type in a WHERE clause if no labels or rel types match it', () => { + const query = `MATCH (n)-[r]-(m) WHERE r IS Rel RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Cow'] }, + }), + ).toEqual([ + { + message: + "Label or relationship type Rel is not present in the database. Make sure you didn't misspell it or that it is available when you run this statement in your application", + offsets: { + end: 32, + start: 29, + }, + range: { + end: { + character: 32, + line: 0, + }, + start: { + character: 29, line: 0, }, }, @@ -219,6 +312,76 @@ describe('Syntactic validation spec', () => { ]); }); + test('Syntax validation does not warn on missing label in a WHERE clause if it is a relationship type', () => { + const query = `MATCH (n) WHERE n IS Person RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + + test('Syntax validation does not warn on missing label in a WHERE clause if it is a label', () => { + const query = `MATCH ()-[r]-() WHERE r IS Dog RETURN r`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + + test('Syntax validation does not warn on missing label in a CREATE', () => { + const query = `CREATE (n: Person) RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + + test('Syntax validation does not warn on missing rel type in a CREATE', () => { + const query = `CREATE (n)-[r:Rel]->(m) RETURN n`; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + + test('Syntax validation does not warn on missing label in a MERGE', () => { + const query = `MERGE (n:Label {name: $value}) + ON CREATE SET n.created = timestamp() + ON MATCH SET + n.accessTime = timestamp() + `; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + + test('Syntax validation does not warn on missing rel type in a MERGE', () => { + const query = 'MERGE (n)-[r:Rel]-(m) RETURN r'; + + expect( + getDiagnosticsForQuery({ + query, + dbSchema: { labels: ['Dog', 'Cat'], relationshipTypes: ['Person'] }, + }), + ).toEqual([]); + }); + test('Syntax validation errors on missing label expression', () => { const query = `MATCH (n:) RETURN n`;