Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapts procedure registry to depend on the cypher version #331

Merged
merged 37 commits into from
Feb 4, 2025
Merged
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
34f2bb8
Altered semantic analysis to use default/query-specified version if a…
anderson4j Jan 13, 2025
1f76037
Merge branch 'main' of https://github.com/neo4j/cypher-language-suppo…
anderson4j Jan 13, 2025
d1d0a48
added tests
anderson4j Jan 15, 2025
d79e282
small refactor, fix defaultLanguage to be more like data according to…
anderson4j Jan 16, 2025
b9fc356
added changeset
anderson4j Jan 16, 2025
d653261
Adds some minor nits
ncordon Jan 21, 2025
33fd518
Adds versioned procedure registry
ncordon Jan 21, 2025
e58d2e5
Updates the semantic analysis to use different procedure registries d…
ncordon Jan 22, 2025
44c0b32
Adds tests for procedures / functions dependant on cypher versions
ncordon Jan 22, 2025
6e7e5c6
Adds tests for completions and signature help being cypher version de…
ncordon Jan 22, 2025
ff25f9e
Makes project compile
ncordon Jan 22, 2025
fbdf5bb
Fixes e2e tests
ncordon Jan 23, 2025
7cacbcb
Merge branch 'main' into polling-versioned-procs-fns
ncordon Jan 23, 2025
9d29a4b
Adds integration test to check the poller and VSCode extension can us…
ncordon Jan 23, 2025
ee324f9
Merge remote-tracking branch 'origin/polling-versioned-procs-fns' int…
ncordon Jan 23, 2025
6c98b22
Fixes e2e test
ncordon Jan 23, 2025
07f20b7
Self review
ncordon Jan 23, 2025
f3b41a1
Adds feature flag to the codemirror wiring
ncordon Jan 24, 2025
662b643
Fixes feature flag
ncordon Jan 26, 2025
cbda4a1
Adds more tests for codemirror
ncordon Jan 26, 2025
ef228ad
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Jan 28, 2025
f18041e
Updates semantic analysis and removes exports
ncordon Jan 28, 2025
d2704ec
Addresses pr review comments
ncordon Jan 29, 2025
f2313a1
Merge branch 'main' into polling-versioned-procs-fns
ncordon Jan 29, 2025
d6d9547
Sets the env variable with cross-env
ncordon Jan 29, 2025
74f5ecb
Updates only needed resolver
ncordon Jan 29, 2025
cacf7a4
Widens timeout
ncordon Jan 30, 2025
fb785f4
Widens timeout even more
ncordon Jan 30, 2025
bdaa8f7
Removes helpers test
ncordon Jan 30, 2025
811d70a
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Jan 30, 2025
3a10389
Forces update
ncordon Jan 30, 2025
f6ba2ef
Increases another timeout
ncordon Jan 31, 2025
b3a8b8b
Gates the test to have the test.only
ncordon Jan 31, 2025
8e00f98
Tries widening all timeouts
ncordon Jan 31, 2025
ee2cd18
Cleans up
ncordon Jan 31, 2025
aa7c1a3
Removes non needed force
ncordon Feb 4, 2025
04430fa
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Addresses pr review comments
ncordon committed Jan 29, 2025
commit d2704ec2a6bf80fc726832689efb3413942e2a02
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ const procedureReturnCompletions = (
cypherVersion: CypherVersion,
): CompletionItem[] => {
return (
dbSchema?.procedures?.[cypherVersion]?.[
dbSchema.procedures?.[cypherVersion]?.[
procedureName
]?.returnDescription?.map((x) => {
return { label: x.name, kind: CompletionItemKind.Variable };
@@ -120,7 +120,7 @@ const functionNameCompletions = (
namespacedCompletion(
candidateRule,
tokens,
dbSchema?.functions?.[cypherVersion] ?? {},
dbSchema.functions?.[cypherVersion] ?? {},
'function',
);

@@ -133,7 +133,7 @@ const procedureNameCompletions = (
namespacedCompletion(
candidateRule,
tokens,
dbSchema?.procedures?.[cypherVersion] ?? {},
dbSchema.procedures?.[cypherVersion] ?? {},
'procedure',
);

@@ -796,7 +796,7 @@ function completeAliasName({
) {
return [
...parameterSuggestions,
...(dbSchema?.aliasNames ?? []).map((aliasName) => ({
...(dbSchema.aliasNames ?? []).map((aliasName) => ({
label: aliasName,
kind: CompletionItemKind.Value,
insertText: backtickDbNameIfNeeded(aliasName),
@@ -861,7 +861,7 @@ function completeSymbolicName({
if (rulesThatAcceptExistingUsers.some((rule) => ruleList.includes(rule))) {
const result = [
...parameterSuggestions,
...(dbSchema?.userNames ?? []).map((userName) => ({
...(dbSchema.userNames ?? []).map((userName) => ({
label: userName,
kind: CompletionItemKind.Value,
})),
@@ -879,7 +879,7 @@ function completeSymbolicName({
if (rulesThatAcceptExistingRoles.some((rule) => ruleList.includes(rule))) {
return [
...parameterSuggestions,
...(dbSchema?.roleNames ?? []).map((roleName) => ({
...(dbSchema.roleNames ?? []).map((roleName) => ({
label: roleName,
kind: CompletionItemKind.Value,
})),
3 changes: 1 addition & 2 deletions packages/language-support/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -212,8 +212,7 @@ export function resolveCypherVersion(
) {
if (_internalFeatureFlags.cypher25) {
const cypherVersion: CypherVersion =
parsedVersion ??
(dbSchema.defaultLanguage ? dbSchema.defaultLanguage : 'CYPHER 5');
parsedVersion ?? dbSchema.defaultLanguage ?? 'CYPHER 5';

return cypherVersion;
} else {
4 changes: 2 additions & 2 deletions packages/language-support/src/signatureHelp.ts
Original file line number Diff line number Diff line change
@@ -206,12 +206,12 @@ export function signatureHelp(
);
if (method.methodType === MethodType.function) {
result = toSignatureHelp(
dbSchema?.functions?.[cypherVersion] ?? {},
dbSchema.functions?.[cypherVersion] ?? {},
method,
);
} else {
result = toSignatureHelp(
dbSchema?.procedures?.[cypherVersion] ?? {},
dbSchema.procedures?.[cypherVersion] ?? {},
method,
);
}
Original file line number Diff line number Diff line change
@@ -49,40 +49,37 @@ function copySettingSeverity(
}));
}

function updateSignatureResolvers(dbSchema: DbSchema) {
if (JSON.stringify(dbSchema) !== JSON.stringify(previousSchema)) {
previousSchema = dbSchema;

cypherVersions.forEach((cypherVersion) => {
const procedures = Object.values(
dbSchema.procedures?.[cypherVersion] ?? {},
);
const functions = Object.values(
dbSchema.functions?.[cypherVersion] ?? {},
);
updateSignatureResolver(
{
procedures: procedures,
functions: functions,
},
cypherVersion,
);
});
}
}
export function wrappedSemanticAnalysis(
query: string,
dbSchema: DbSchema,
parsedVersion?: CypherVersion,
): SemanticAnalysisResult {
try {
if (JSON.stringify(dbSchema) !== JSON.stringify(previousSchema)) {
previousSchema = dbSchema;

cypherVersions.forEach((cypherVersion) => {
const procedures = Object.values(
dbSchema?.procedures?.[cypherVersion] ?? {},
);
const functions = Object.values(
dbSchema?.functions?.[cypherVersion] ?? {},
);
updateSignatureResolver(
{
procedures: procedures,
functions: functions,
},
cypherVersion,
);
});
}

let cypherVersion = 'CYPHER 5';
const defaultVersion = dbSchema.defaultLanguage?.toUpperCase();
updateSignatureResolvers(dbSchema);

if (parsedVersion) {
cypherVersion = parsedVersion;
} else if (dbSchema.defaultLanguage) {
cypherVersion = defaultVersion;
}
const defaultVersion = dbSchema?.defaultLanguage;
const cypherVersion = parsedVersion ?? defaultVersion ?? 'CYPHER 5';
const semanticErrorsResult = analyzeQuery(
query,
cypherVersion.toLowerCase(),
Original file line number Diff line number Diff line change
@@ -8,12 +8,15 @@ import { testData } from '../testData';
import { testCompletions } from './completionAssertionHelpers';

describe('function invocations', () => {
let isCypher25: boolean;

beforeAll(() => {
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
_internalFeatureFlags.cypher25 = isCypher25;
});

const dbSchema: DbSchema = testData.mockSchema;
Original file line number Diff line number Diff line change
@@ -8,12 +8,15 @@ import { testData } from '../testData';
import { testCompletions } from './completionAssertionHelpers';

describe('Procedures auto-completion', () => {
let isCypher25: boolean;

beforeAll(() => {
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
_internalFeatureFlags.cypher25 = isCypher25;
});

const procedures = testData.mockSchema.procedures;
27 changes: 22 additions & 5 deletions packages/language-support/src/tests/consoleCommands.test.ts
Original file line number Diff line number Diff line change
@@ -36,12 +36,15 @@ function expectErrorMessage(query: string, msg: string) {
}

describe('sanity checks', () => {
let consoleCommands: boolean;

beforeAll(() => {
consoleCommands = _internalFeatureFlags.consoleCommands;
_internalFeatureFlags.consoleCommands = true;
});

afterAll(() => {
_internalFeatureFlags.consoleCommands = false;
_internalFeatureFlags.consoleCommands = consoleCommands;
});

test('parses simple commands without args ', () => {
@@ -219,11 +222,14 @@ describe('sanity checks', () => {
});

describe(':use', () => {
let consoleCommands: boolean;

beforeAll(() => {
consoleCommands = _internalFeatureFlags.consoleCommands;
_internalFeatureFlags.consoleCommands = true;
});
afterAll(() => {
_internalFeatureFlags.consoleCommands = false;
_internalFeatureFlags.consoleCommands = consoleCommands;
});
test('parses without arg', () => {
expectParsedCommands(':use', [{ type: 'use' }]);
@@ -285,11 +291,14 @@ describe(':use', () => {
});

describe('parameters', () => {
let consoleCommands: boolean;

beforeAll(() => {
consoleCommands = _internalFeatureFlags.consoleCommands;
_internalFeatureFlags.consoleCommands = true;
});
afterAll(() => {
_internalFeatureFlags.consoleCommands = false;
_internalFeatureFlags.consoleCommands = consoleCommands;
});
test('basic param usage', () => {
expectParsedCommands(':param', [{ type: 'list-parameters' }]);
@@ -550,12 +559,15 @@ describe('parameters', () => {
});

describe('server', () => {
let consoleCommands: boolean;

beforeAll(() => {
consoleCommands = _internalFeatureFlags.consoleCommands;
_internalFeatureFlags.consoleCommands = true;
});

afterAll(() => {
_internalFeatureFlags.consoleCommands = false;
_internalFeatureFlags.consoleCommands = consoleCommands;
});

test('basic server usage', () => {
@@ -655,12 +667,17 @@ describe('server', () => {
});

describe('command parser also handles cypher', () => {
let consoleCommands: boolean;

beforeAll(() => {
consoleCommands = _internalFeatureFlags.consoleCommands;
_internalFeatureFlags.consoleCommands = true;
});

afterAll(() => {
_internalFeatureFlags.consoleCommands = false;
_internalFeatureFlags.consoleCommands = consoleCommands;
});

test('parses cypher', () => {
expectParsedCommands('MATCH (n) RETURN n', [
{ statement: 'MATCH (n) RETURN n', type: 'cypher' },
5 changes: 4 additions & 1 deletion packages/language-support/src/tests/signatureHelp.test.ts
Original file line number Diff line number Diff line change
@@ -22,12 +22,15 @@ export function testSignatureHelp(
}

describe('Procedures signature help', () => {
let isCypher25: boolean;

beforeAll(() => {
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
_internalFeatureFlags.cypher25 = isCypher25;
});

const dbSchema = testData.mockSchema;
Original file line number Diff line number Diff line change
@@ -4,12 +4,15 @@ import { testData } from '../testData';
import { getDiagnosticsForQuery } from './helpers';

describe('Functions semantic validation spec', () => {
let isCypher25: boolean;

beforeAll(() => {
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
_internalFeatureFlags.cypher25 = isCypher25;
});

test('Syntax validation warns on deprecated function when database can be contacted and deprecated by is not present', () => {
Original file line number Diff line number Diff line change
@@ -3,12 +3,15 @@ import { testData } from '../testData';
import { getDiagnosticsForQuery } from './helpers';

describe('Procedures semantic validation spec', () => {
let isCypher25: boolean;

beforeAll(() => {
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = isCypher25;
});

test('Syntax validation warns on deprecated procedure when database can be contacted', () => {
Original file line number Diff line number Diff line change
@@ -3,12 +3,15 @@ import { testData } from '../testData';
import { getDiagnosticsForQuery } from './helpers';

describe('Semantic validation spec', () => {
let isCypher25: boolean;

beforeAll(() => {
isCypher25 = _internalFeatureFlags.cypher25;
_internalFeatureFlags.cypher25 = true;
});

afterAll(() => {
_internalFeatureFlags.cypher25 = false;
_internalFeatureFlags.cypher25 = isCypher25;
});

test('Semantic analysis is dependant on cypher version', () => {
4 changes: 2 additions & 2 deletions packages/schema-poller/src/metadataPoller.ts
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@ export class MetadataPoller {
private readonly connection: Neo4jConnection,
private readonly events: EventEmitter,
) {
const isNewerNeo4j =
const supportsCypherAnnotation =
_internalFeatureFlags.cypher25 ||
databases.find((db) => db.defaultLanguage !== undefined) !== undefined;

@@ -160,7 +160,7 @@ export class MetadataPoller {
},
});

const versions: (CypherVersion | undefined)[] = isNewerNeo4j
const versions: (CypherVersion | undefined)[] = supportsCypherAnnotation
? cypherVersions
: [undefined];

2 changes: 1 addition & 1 deletion packages/schema-poller/src/queries/databases.ts
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ export function listDatabases(): ExecuteQueryArgs<{
map(record) {
const obj = record.toObject();
if (obj.defaultLanguage) {
obj.defaultLanguage = (obj.defaultLanguage as string).toLowerCase();
obj.defaultLanguage = (obj.defaultLanguage as string).toUpperCase();
}
return obj as Database;
},