From 2fa77f4df5cd158b1bf2e632d7f6f1bb3657a5c0 Mon Sep 17 00:00:00 2001 From: Isak Date: Thu, 23 Oct 2025 14:18:01 +0200 Subject: [PATCH 1/3] move to print Point objects from the driver as point.toString() in both vscode and query-tools --- .../src/data-transforms/record-to-string.ts | 29 +++++-------------- packages/vscode-extension/src/typeUtils.ts | 4 ++- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/packages/query-tools/src/data-transforms/record-to-string.ts b/packages/query-tools/src/data-transforms/record-to-string.ts index cc88e68f3..7ac308084 100644 --- a/packages/query-tools/src/data-transforms/record-to-string.ts +++ b/packages/query-tools/src/data-transforms/record-to-string.ts @@ -1,4 +1,4 @@ -import type { Node, Path, Point, Relationship } from 'neo4j-driver'; +import type { Node, Path, Relationship } from 'neo4j-driver'; import { isInt, isNode, isPath, isPoint, isRelationship } from 'neo4j-driver'; import type { @@ -12,11 +12,6 @@ import { } from '../types/cypher-data-types'; import { formatFloat } from './format-float'; -const spacialFormat = (p: Point): string => { - const zString = p.z !== undefined ? `, z:${p.z}` : ''; - return `point({srid:${p.srid.toString()}, x:${p.x}, y:${p.y}${zString}})`; -}; - export function propertyToString( property: CypherProperty, quoteStrings = true, @@ -29,13 +24,13 @@ export function propertyToString( if (property === null) { return 'null'; } - if (typeof property === 'boolean') { - return property.toString(); - } - if (isInt(property)) { - return property.toString(); - } - if (typeof property === 'bigint') { + if ( + typeof property === 'boolean' || + isInt(property) || + typeof property === 'bigint' || + isCypherTemporalType(property) || + isPoint(property) + ) { return property.toString(); } if (typeof property === 'number') { @@ -53,14 +48,6 @@ export function propertyToString( return 'ByteArray'; } - if (isCypherTemporalType(property)) { - return property.toString(); - } - - if (isPoint(property)) { - return spacialFormat(property); - } - // This case shouldn't be used, but added as a fallback return String(property); } diff --git a/packages/vscode-extension/src/typeUtils.ts b/packages/vscode-extension/src/typeUtils.ts index 3209da146..428586f40 100644 --- a/packages/vscode-extension/src/typeUtils.ts +++ b/packages/vscode-extension/src/typeUtils.ts @@ -11,6 +11,7 @@ import { isInt, isLocalDateTime, isLocalTime, + isPoint, isTime, } from 'neo4j-driver'; import { isDate } from 'util/types'; @@ -43,7 +44,8 @@ function valueToNativeType(value: unknown) { isTime(value) || isLocalDateTime(value) || isLocalTime(value) || - isDuration(value) + isDuration(value) || + isPoint(value) ) { value = value.toString(); } else if ( From 488a7417fd5260da42f61de5363a01dfe182bd4e Mon Sep 17 00:00:00 2001 From: Isak Date: Tue, 28 Oct 2025 12:31:30 +0100 Subject: [PATCH 2/3] return to spacialFormat + add .0 to ints, so we get copy-pastable object that looks like in cypher shell --- .../src/data-transforms/record-to-string.ts | 21 ++++++++++++++++--- packages/query-tools/src/index.ts | 5 ++++- packages/vscode-extension/src/typeUtils.ts | 6 ++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/query-tools/src/data-transforms/record-to-string.ts b/packages/query-tools/src/data-transforms/record-to-string.ts index 7ac308084..88e607d34 100644 --- a/packages/query-tools/src/data-transforms/record-to-string.ts +++ b/packages/query-tools/src/data-transforms/record-to-string.ts @@ -1,4 +1,4 @@ -import type { Node, Path, Relationship } from 'neo4j-driver'; +import type { Node, Path, Point, Relationship } from 'neo4j-driver'; import { isInt, isNode, isPath, isPoint, isRelationship } from 'neo4j-driver'; import type { @@ -12,6 +12,19 @@ import { } from '../types/cypher-data-types'; import { formatFloat } from './format-float'; +export const spacialFormat = (p: Point): string => { + const xString = floatifyIfInt(p.x); + const yString = floatifyIfInt(p.y); + const zString = p.z !== undefined ? `, z:${floatifyIfInt(p.z)}` : ''; + return `point({srid:${p.srid.toString()}, x:${xString}, y:${yString}${zString}})`; +}; + +const floatifyIfInt = (x: number) => { + const xFixed1 = x.toFixed(1); + const xString = x.toString(); + return Number(xString) === Number(xFixed1) ? xFixed1 : xString; +}; + export function propertyToString( property: CypherProperty, quoteStrings = true, @@ -28,11 +41,13 @@ export function propertyToString( typeof property === 'boolean' || isInt(property) || typeof property === 'bigint' || - isCypherTemporalType(property) || - isPoint(property) + isCypherTemporalType(property) ) { return property.toString(); } + if (isPoint(property)) { + spacialFormat(property); + } if (typeof property === 'number') { return formatFloat(property); } diff --git a/packages/query-tools/src/index.ts b/packages/query-tools/src/index.ts index 87929433a..7f7a84ad8 100644 --- a/packages/query-tools/src/index.ts +++ b/packages/query-tools/src/index.ts @@ -11,7 +11,10 @@ export { getPropertyTypeDisplayName, } from './data-transforms/cypher-type-names'; export type { CypherDataTypeName } from './data-transforms/cypher-type-names'; -export { cypherDataToString } from './data-transforms/record-to-string'; +export { + cypherDataToString, + spacialFormat, +} from './data-transforms/record-to-string'; export type { CypherProperty } from './data-types/cypher-data-types'; export type { ConnectedMetadataPoller as CypherMetadataPoller, diff --git a/packages/vscode-extension/src/typeUtils.ts b/packages/vscode-extension/src/typeUtils.ts index 428586f40..fff993655 100644 --- a/packages/vscode-extension/src/typeUtils.ts +++ b/packages/vscode-extension/src/typeUtils.ts @@ -15,6 +15,7 @@ import { isTime, } from 'neo4j-driver'; import { isDate } from 'util/types'; +import { spacialFormat } from '@neo4j-cypher/query-tools'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export function toNativeTypes(properties: Record) { @@ -44,10 +45,11 @@ function valueToNativeType(value: unknown) { isTime(value) || isLocalDateTime(value) || isLocalTime(value) || - isDuration(value) || - isPoint(value) + isDuration(value) ) { value = value.toString(); + } else if (isPoint(value)) { + value = spacialFormat(value); } else if ( typeof value === 'object' && value !== undefined && From 21f5fc8f5f0bf2a7c737e8e2203e75eb5e9ffcf2 Mon Sep 17 00:00:00 2001 From: Isak Date: Tue, 28 Oct 2025 15:42:40 +0100 Subject: [PATCH 3/3] swap out my float formatting for existing one --- .../src/data-transforms/record-to-string.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/query-tools/src/data-transforms/record-to-string.ts b/packages/query-tools/src/data-transforms/record-to-string.ts index 88e607d34..51da5a082 100644 --- a/packages/query-tools/src/data-transforms/record-to-string.ts +++ b/packages/query-tools/src/data-transforms/record-to-string.ts @@ -13,16 +13,10 @@ import { import { formatFloat } from './format-float'; export const spacialFormat = (p: Point): string => { - const xString = floatifyIfInt(p.x); - const yString = floatifyIfInt(p.y); - const zString = p.z !== undefined ? `, z:${floatifyIfInt(p.z)}` : ''; - return `point({srid:${p.srid.toString()}, x:${xString}, y:${yString}${zString}})`; -}; - -const floatifyIfInt = (x: number) => { - const xFixed1 = x.toFixed(1); - const xString = x.toString(); - return Number(xString) === Number(xFixed1) ? xFixed1 : xString; + const zString = p.z !== undefined ? `, z:${formatFloat(p.z)}` : ''; + return `point({srid:${p.srid.toString()}, x:${formatFloat( + p.x, + )}, y:${formatFloat(p.y)}${zString}})`; }; export function propertyToString(