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

Commit

Permalink
Merge pull request #341 from michaeldgraham/master
Browse files Browse the repository at this point in the history
Spatial filters
  • Loading branch information
johnymontana authored Nov 10, 2019
2 parents d71d73b + 3a5ebfb commit c4f6a21
Show file tree
Hide file tree
Showing 9 changed files with 623 additions and 127 deletions.
107 changes: 70 additions & 37 deletions src/augment/input-values.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
buildEnumType,
buildEnumValue
} from './ast';
import { isNeo4jPropertyType } from './types/types';
import {
isNeo4jTemporalType,
isNeo4jPointType,
Neo4jTypeName
} from './types/types';
import { isCypherField } from './directives';
import {
TypeWrappers,
Expand All @@ -18,9 +22,10 @@ import {
isStringField,
isBooleanField,
isTemporalField,
getFieldDefinition
getFieldDefinition,
isSpatialField
} from './fields';

import { SpatialType, Neo4jPointDistanceFilter } from './types/spatial';
/**
* An enum describing the names of the input value definitions
* used for the field argument AST for data result pagination
Expand Down Expand Up @@ -326,10 +331,24 @@ const buildPropertyFilters = ({
}) => {
let filters = [];
if (
isSpatialField({ type: outputType }) ||
isNeo4jPointType({ type: outputType })
) {
filters = buildFilters({
fieldName,
fieldConfig: {
name: fieldName,
type: {
name: outputType
}
},
filterTypes: ['not', ...Object.values(Neo4jPointDistanceFilter)]
});
} else if (
isIntegerField({ type: outputType }) ||
isFloatField({ type: outputType }) ||
isTemporalField({ type: outputType }) ||
isNeo4jPropertyType({ type: outputType })
isNeo4jTemporalType({ type: outputType })
) {
filters = buildFilters({
fieldName,
Expand All @@ -339,7 +358,7 @@ const buildPropertyFilters = ({
name: outputType
}
},
filterTypes: ['_not', '_in', '_not_in', '_lt', '_lte', '_gt', '_gte']
filterTypes: ['not', 'in', 'not_in', 'lt', 'lte', 'gt', 'gte']
});
} else if (isBooleanField({ type: outputType })) {
filters = buildFilters({
Expand All @@ -350,7 +369,7 @@ const buildPropertyFilters = ({
name: outputType
}
},
filterTypes: ['_not']
filterTypes: ['not']
});
} else if (isStringField({ kind: outputKind, type: outputType })) {
if (outputKind === Kind.ENUM_TYPE_DEFINITION) {
Expand All @@ -362,7 +381,7 @@ const buildPropertyFilters = ({
name: outputType
}
},
filterTypes: ['_not', '_in', '_not_in']
filterTypes: ['not', 'in', 'not_in']
});
} else {
filters = buildFilters({
Expand All @@ -374,15 +393,15 @@ const buildPropertyFilters = ({
}
},
filterTypes: [
'_not',
'_in',
'_not_in',
'_contains',
'_not_contains',
'_starts_with',
'_not_starts_with',
'_ends_with',
'_not_ends_with'
'not',
'in',
'not_in',
'contains',
'not_contains',
'starts_with',
'not_starts_with',
'ends_with',
'not_ends_with'
]
});
}
Expand All @@ -394,25 +413,39 @@ const buildPropertyFilters = ({
* Builds the input value definitions that compose input object types
* used by filtering arguments
*/
export const buildFilters = ({ fieldName, fieldConfig, filterTypes = [] }) => [
buildInputValue({
name: buildName({ name: fieldConfig.name }),
type: buildNamedType(fieldConfig.type)
}),
...filterTypes.map(filter => {
let wrappers = {};
if (filter === '_in' || filter === '_not_in') {
wrappers = {
[TypeWrappers.NON_NULL_NAMED_TYPE]: true,
[TypeWrappers.LIST_TYPE]: true
};
}
return buildInputValue({
name: buildName({ name: `${fieldName}${filter}` }),
type: buildNamedType({
name: fieldConfig.type.name,
wrappers
export const buildFilters = ({ fieldName, fieldConfig, filterTypes = [] }) => {
return filterTypes.reduce(
(inputValues, name) => {
const filterName = `${fieldName}_${name}`;
const isPointDistanceFilter = Object.values(
Neo4jPointDistanceFilter
).some(distanceFilter => distanceFilter === name);
const isListFilter = name === 'in' || name === 'not_in';
let wrappers = {};
if (isListFilter) {
wrappers = {
[TypeWrappers.NON_NULL_NAMED_TYPE]: true,
[TypeWrappers.LIST_TYPE]: true
};
} else if (isPointDistanceFilter) {
fieldConfig.type.name = `${Neo4jTypeName}${SpatialType.POINT}DistanceFilter`;
}
inputValues.push(
buildInputValue({
name: buildName({ name: filterName }),
type: buildNamedType({
name: fieldConfig.type.name,
wrappers
})
})
);
return inputValues;
},
[
buildInputValue({
name: buildName({ name: fieldConfig.name }),
type: buildNamedType(fieldConfig.type)
})
});
})
];
]
);
};
12 changes: 2 additions & 10 deletions src/augment/types/relationship/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,7 @@ export const buildRelationshipFilters = ({
name: outputType
}
},
filterTypes: [
'_not',
'_in',
'_not_in',
'_some',
'_none',
'_single',
'_every'
]
filterTypes: ['not', 'in', 'not_in', 'some', 'none', 'single', 'every']
});
} else {
filters = buildFilters({
Expand All @@ -304,7 +296,7 @@ export const buildRelationshipFilters = ({
name: outputType
}
},
filterTypes: ['_not', '_in', '_not_in']
filterTypes: ['not', 'in', 'not_in']
});
}
}
Expand Down
64 changes: 62 additions & 2 deletions src/augment/types/spatial.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { GraphQLInt, GraphQLString } from 'graphql';
import { buildNeo4jTypes } from '../types/types';
import { GraphQLInt, GraphQLString, GraphQLFloat } from 'graphql';
import { buildNeo4jTypes, Neo4jTypeName } from '../types/types';
import {
buildName,
buildNamedType,
buildInputValue,
buildInputObjectType
} from '../ast';
import { TypeWrappers } from '../fields';

/**
* An enum describing the name of the Neo4j Point type
Expand Down Expand Up @@ -38,12 +45,29 @@ export const Neo4jPoint = {
[Neo4jPointField.SRID]: GraphQLInt.name
};

export const Neo4jPointDistanceFilter = {
DISTANCE: 'distance',
DISTANCE_LESS_THAN: 'distance_lt',
DISTANCE_LESS_THAN_OR_EQUAL: 'distance_lte',
DISTANCE_GREATER_THAN: 'distance_gt',
DISTANCE_GREATER_THAN_OR_EQUAL: 'distance_gte'
};

export const Neo4jPointDistanceArgument = {
POINT: 'point',
DISTANCE: 'distance'
};

/**
* The main export for building the GraphQL input and output type definitions
* for Neo4j Temporal property types
*/
export const augmentSpatialTypes = ({ typeMap, config = {} }) => {
config.spatial = decideSpatialConfig({ config });
typeMap = buildSpatialDistanceFilterInputType({
typeMap,
config
});
return buildNeo4jTypes({
typeMap,
neo4jTypes: SpatialType,
Expand All @@ -69,3 +93,39 @@ const decideSpatialConfig = ({ config }) => {
}
return defaultConfig;
};

/**
* Builds the AST for the input object definition used for
* providing arguments to the spatial filters that use the
* distance Cypher function
*/
const buildSpatialDistanceFilterInputType = ({ typeMap = {}, config }) => {
if (config.spatial.point) {
const typeName = `${Neo4jTypeName}${SpatialType.POINT}DistanceFilter`;
// Overwrite
typeMap[typeName] = buildInputObjectType({
name: buildName({ name: typeName }),
fields: [
buildInputValue({
name: buildName({ name: Neo4jPointDistanceArgument.POINT }),
type: buildNamedType({
name: `${Neo4jTypeName}${SpatialType.POINT}Input`,
wrappers: {
[TypeWrappers.NON_NULL_NAMED_TYPE]: true
}
})
}),
buildInputValue({
name: buildName({ name: Neo4jPointDistanceArgument.DISTANCE }),
type: buildNamedType({
name: GraphQLFloat.name,
wrappers: {
[TypeWrappers.NON_NULL_NAMED_TYPE]: true
}
})
})
]
});
}
return typeMap;
};
Loading

0 comments on commit c4f6a21

Please sign in to comment.