Skip to content
This repository was archived by the owner on Sep 3, 2021. It is now read-only.

Commit 42f6ca3

Browse files
authoredOct 31, 2019
Merge pull request #334 from michaeldgraham/master
Initial spatial support using Point type
2 parents ed82d31 + c5e9515 commit 42f6ca3

15 files changed

+1253
-297
lines changed
 

‎example/apollo-server/movies-schema.js

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type Movie {
2020
actors(first: Int = 3, offset: Int = 0): [Actor] @relation(name: "ACTED_IN", direction:"IN")
2121
avgStars: Float
2222
filmedIn: State @relation(name: "FILMED_IN", direction: "OUT")
23+
location: Point
24+
locations: [Point]
2325
scaleRating(scale: Int = 3): Float @cypher(statement: "WITH $this AS this RETURN $scale * this.imdbRating")
2426
scaleRatingFloat(scale: Float = 1.5): Float @cypher(statement: "WITH $this AS this RETURN $scale * this.imdbRating")
2527
}
@@ -68,6 +70,13 @@ type OnlyDate {
6870
date: Date
6971
}
7072
73+
type SpatialNode {
74+
pointKey: Point
75+
point: Point
76+
spatialNodes(pointKey: Point): [SpatialNode]
77+
@relation(name: "SPATIAL", direction: OUT)
78+
}
79+
7180
type Book {
7281
genre: BookGenre
7382
}

‎src/augment/fields.js

+7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const isPropertyTypeField = ({ kind, type }) =>
1919
isBooleanField({ type }) ||
2020
isCustomScalarField({ kind }) ||
2121
isTemporalField({ type }) ||
22+
isSpatialField({ type }) ||
2223
isNeo4jPropertyType({ type });
2324

2425
export const isIntegerField = ({ type }) =>
@@ -34,9 +35,15 @@ export const isStringField = ({ kind, type }) =>
3435
export const isBooleanField = ({ type }) =>
3536
Neo4jDataType.PROPERTY[type] === 'Boolean';
3637

38+
export const isNeo4jTypeField = ({ type }) =>
39+
isTemporalField({ type }) || isSpatialField({ type });
40+
3741
export const isTemporalField = ({ type }) =>
3842
Neo4jDataType.PROPERTY[type] === 'Temporal';
3943

44+
export const isSpatialField = ({ type }) =>
45+
Neo4jDataType.PROPERTY[type] === 'Spatial';
46+
4047
export const isNeo4jIDField = ({ name }) => name === Neo4jSystemIDField;
4148

4249
export const isCustomScalarField = ({ kind }) =>

‎src/augment/types/spatial.js

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { GraphQLInt, GraphQLString } from 'graphql';
2+
import { buildNeo4jTypes } from '../types/types';
3+
4+
/**
5+
* An enum describing the name of the Neo4j Point type
6+
*/
7+
export const SpatialType = {
8+
POINT: 'Point'
9+
};
10+
11+
/**
12+
* An enum describing the property names of the Neo4j Point type
13+
* See: https://neo4j.com/docs/cypher-manual/current/syntax/spatial/#cypher-spatial-instants
14+
*/
15+
const Neo4jPointField = {
16+
X: 'x',
17+
Y: 'y',
18+
Z: 'z',
19+
LONGITUDE: 'longitude',
20+
LATITUDE: 'latitude',
21+
HEIGHT: 'height',
22+
CRS: 'crs',
23+
SRID: 'srid'
24+
};
25+
26+
/**
27+
* A map of the Neo4j Temporal Time type fields to their respective
28+
* GraphQL types
29+
*/
30+
export const Neo4jPoint = {
31+
[Neo4jPointField.X]: GraphQLInt.name,
32+
[Neo4jPointField.Y]: GraphQLInt.name,
33+
[Neo4jPointField.Z]: GraphQLInt.name,
34+
[Neo4jPointField.LONGITUDE]: GraphQLInt.name,
35+
[Neo4jPointField.LATITUDE]: GraphQLInt.name,
36+
[Neo4jPointField.HEIGHT]: GraphQLInt.name,
37+
[Neo4jPointField.CRS]: GraphQLString.name,
38+
[Neo4jPointField.SRID]: GraphQLInt.name
39+
};
40+
41+
/**
42+
* The main export for building the GraphQL input and output type definitions
43+
* for Neo4j Temporal property types
44+
*/
45+
export const augmentSpatialTypes = ({ typeMap, config = {} }) => {
46+
config.spatial = decideSpatialConfig({ config });
47+
return buildNeo4jTypes({
48+
typeMap,
49+
neo4jTypes: SpatialType,
50+
config: config.spatial
51+
});
52+
};
53+
54+
/**
55+
* A helper function for ensuring a fine-grained spatial
56+
* configmration
57+
*/
58+
const decideSpatialConfig = ({ config }) => {
59+
let defaultConfig = {
60+
point: true
61+
};
62+
const providedConfig = config ? config.spatial : defaultConfig;
63+
if (typeof providedConfig === 'boolean') {
64+
if (providedConfig === false) {
65+
defaultConfig.point = false;
66+
}
67+
} else if (typeof providedConfig === 'object') {
68+
defaultConfig = providedConfig;
69+
}
70+
return defaultConfig;
71+
};

‎src/augment/types/temporal.js

+15-78
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { GraphQLInt, GraphQLString } from 'graphql';
2-
import { Neo4jTypeName, buildNeo4jType } from '../types/types';
3-
import { buildName, buildField, buildNamedType, buildInputValue } from '../ast';
2+
import { buildNeo4jTypes } from '../types/types';
43

54
/**
65
* An enum describing the names of Neo4j Temporal types
6+
* See: https://neo4j.com/docs/cypher-manual/current/syntax/temporal/#cypher-temporal-instants
77
*/
88
export const TemporalType = {
99
TIME: 'Time',
@@ -16,7 +16,7 @@ export const TemporalType = {
1616
/**
1717
* An enum describing the property names of the Neo4j Time type
1818
*/
19-
const Neo4jTimeField = {
19+
export const Neo4jTimeField = {
2020
HOUR: 'hour',
2121
MINUTE: 'minute',
2222
SECOND: 'second',
@@ -29,26 +29,17 @@ const Neo4jTimeField = {
2929
/**
3030
* An enum describing the property names of the Neo4j Date type
3131
*/
32-
const Neo4jDateField = {
32+
export const Neo4jDateField = {
3333
YEAR: 'year',
3434
MONTH: 'month',
3535
DAY: 'day'
3636
};
3737

38-
/**
39-
* An enum describing the names of fields computed and added to the input
40-
* and output type definitions representing non-scalar Neo4j property types
41-
* TODO support for the Neo4j Point data type should also use this
42-
*/
43-
export const Neo4jTypeFormatted = {
44-
FORMATTED: 'formatted'
45-
};
46-
4738
/**
4839
* A map of the Neo4j Temporal Time type fields to their respective
4940
* GraphQL types
5041
*/
51-
const Neo4jTime = {
42+
export const Neo4jTime = {
5243
[Neo4jTimeField.HOUR]: GraphQLInt.name,
5344
[Neo4jTimeField.MINUTE]: GraphQLInt.name,
5445
[Neo4jTimeField.SECOND]: GraphQLInt.name,
@@ -62,86 +53,32 @@ const Neo4jTime = {
6253
* A map of the Neo4j Temporal Date type fields to their respective
6354
* GraphQL types
6455
*/
65-
const Neo4jDate = {
56+
export const Neo4jDate = {
6657
[Neo4jDateField.YEAR]: GraphQLInt.name,
6758
[Neo4jDateField.MONTH]: GraphQLInt.name,
6859
[Neo4jDateField.DAY]: GraphQLInt.name
6960
};
7061

7162
/**
7263
* The main export for building the GraphQL input and output type definitions
73-
* for the Neo4j Temporal property types. Each TemporalType can be constructed
74-
* using either or both of the Time and Date type fields.
64+
* for Neo4j Temporal property types. Each TemporalType can be constructed
65+
* using either or both of the Time and Date type fields
7566
*/
76-
export const buildTemporalTypes = ({ typeMap, config = {} }) => {
77-
config.temporal = decideTemporalConfig(config);
78-
const temporalConfig = config.temporal;
79-
Object.values(TemporalType).forEach(typeName => {
80-
const typeNameLower = typeName.toLowerCase();
81-
if (temporalConfig[typeNameLower] === true) {
82-
const objectTypeName = `${Neo4jTypeName}${typeName}`;
83-
const inputTypeName = `${objectTypeName}Input`;
84-
let fields = [];
85-
if (typeName === TemporalType.DATE) {
86-
fields = Object.entries(Neo4jDate);
87-
} else if (typeName === TemporalType.TIME) {
88-
fields = Object.entries(Neo4jTime);
89-
} else if (typeName === TemporalType.LOCALTIME) {
90-
fields = Object.entries({
91-
...Neo4jTime
92-
}).filter(([name]) => name !== Neo4jTimeField.TIMEZONE);
93-
} else if (typeName === TemporalType.DATETIME) {
94-
fields = Object.entries({
95-
...Neo4jDate,
96-
...Neo4jTime
97-
});
98-
} else if (typeName === TemporalType.LOCALDATETIME) {
99-
fields = Object.entries({
100-
...Neo4jDate,
101-
...Neo4jTime
102-
}).filter(([name]) => name !== Neo4jTimeField.TIMEZONE);
103-
}
104-
let inputFields = [];
105-
let outputFields = [];
106-
fields.forEach(([fieldName, fieldType]) => {
107-
const fieldNameLower = fieldName.toLowerCase();
108-
const fieldConfig = {
109-
name: buildName({ name: fieldNameLower }),
110-
type: buildNamedType({
111-
name: fieldType
112-
})
113-
};
114-
inputFields.push(buildInputValue(fieldConfig));
115-
outputFields.push(buildField(fieldConfig));
116-
});
117-
const formattedFieldConfig = {
118-
name: buildName({
119-
name: Neo4jTypeFormatted.FORMATTED
120-
}),
121-
type: buildNamedType({
122-
name: GraphQLString.name
123-
})
124-
};
125-
inputFields.push(buildInputValue(formattedFieldConfig));
126-
outputFields.push(buildField(formattedFieldConfig));
127-
typeMap = buildNeo4jType({
128-
inputTypeName,
129-
inputFields,
130-
objectTypeName,
131-
outputFields,
132-
typeMap
133-
});
134-
}
67+
export const augmentTemporalTypes = ({ typeMap, config = {} }) => {
68+
config.temporal = decideTemporalConfig({ config });
69+
return buildNeo4jTypes({
70+
typeMap,
71+
neo4jTypes: TemporalType,
72+
config: config.temporal
13573
});
136-
return typeMap;
13774
};
13875

13976
/**
14077
* A helper function for ensuring a fine-grained temporal
14178
* configmration, used to simplify checking it
14279
* throughout the augmnetation process
14380
*/
144-
const decideTemporalConfig = config => {
81+
const decideTemporalConfig = ({ config }) => {
14582
let defaultConfig = {
14683
time: true,
14784
date: true,

0 commit comments

Comments
 (0)