-
Notifications
You must be signed in to change notification settings - Fork 49
Add support for spatial point values and distance comparisons #94
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
Add support for spatial point values and distance comparisons #94
Conversation
FYI Cypher-DSL 2020.0.1 with your PR should be on central soonish.
|
if (op != null) { | ||
return ExpressionPredicate(definedField.name, op, value, definedField) | ||
if (definedField.type.isNeo4jType()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we extract the block into a method?
"$not$variable.${name.quote()} ${op.op} \$$paramName" | ||
val appendField = if (nestedField != null) { | ||
paramName += "_$nestedField" | ||
".$nestedField" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paramNames can't contain dots ?
is there a better way than modfiying the paramName?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they can, but it breaks the "style" so I've chosen to use underscore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they can't, since neo4j will try to resolve everything behind the .
as property of a scalar type
val condition = conditionField.op.conditionCreator(prop, parameter) | ||
filterParams[parameter.name] = conditionField.queryField.value.toJavaValue() | ||
where = conditionAdder(where, condition) | ||
if (conditionField.fieldDefinition.type.isNeo4jType() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have a lot of places where larger chunks of code related to spatial / distance are now spread through the code-base like here, would be there any way of extracting them/putting them together so that the implementation doesn't leak into all these places?
} else { | ||
val parameter = Cypher.parameter(variablePrefix + "_" + conditionField.queryField.name) | ||
var name = conditionField.fieldDefinition.name | ||
if (appendObjectFieldName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also more boolean conditions like this one that are passed through which make the code much harder to understand and maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
esp. as they only communicate the what but not the why and what does it mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it would also be good if we found a way to co-locate these code-chunks for the different operations (mostly expressions) with the enums / expression types that were originally meant for keeping that functionality isolated.
queriedFields.remove(queryFieldName)?.let { (index, objectField) -> | ||
Predicate(predicate, objectField, definedField, index) | ||
queriedFields[queryFieldName]?.let { (index, objectField) -> | ||
if (predicate.requireParam xor (objectField.value !is NullValue)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first time I've seen an XOR in real code. esp. xor with negations is kinda ouch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:-)
Predicate(predicate, objectField, definedField, index) | ||
queriedFields[queryFieldName]?.let { (index, objectField) -> | ||
if (predicate.requireParam xor (objectField.value !is NullValue)) { | ||
// if we got a value but the predicate requires none |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we turn the comment into code instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did this before the xor
but the condition was even uglier than the xor. Do you really don't like the xor
so much.
In my opinion this line is even worse:
if ((predicate.requireParam && objectField.value is NullValue) || (!predicate.requireParam && objectField.value !is NullValue))
is Float -> v.toDouble(); is Int -> v.toLong(); else -> v | ||
is Float -> v.toDouble() | ||
is Int -> v.toLong() | ||
is List<*> -> v.map { fixNumber(it) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably for Iterable/Sequence?
@@ -214,6 +229,42 @@ type _Neo4jLocalTime { | |||
second: Int | |||
} | |||
|
|||
type _Neo4jPoint { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we can minimize that.
Either by splitting it into 2 point types.
And removing / limiting a bit of the capabilities (e.g. coordinate systems) ?
/cc @johnymontana
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks to match the point type used in neo4j-graphql.js, which is good. I don't think we want multiple GraphQL point types, and instead we should match the Neo4j database point type.
I think the issue @jexp is getting at here is that there are many optional fields on the point type. This stems from the fact that there aren't separate database types for 2D, or 3D - instead they are the same type. So to match that behavior the GraphQL type needs to have these optional fields. One thing that could be done in the future to simplify this is to use a GraphQL union input type (coming to the GraphQL spec soon) for the mutations and filters, which would have a LatLon, xyz, etc types wrapped up in a point union input type which I think would make it more clear what the various options for specifying a point type are.
In most cases I think users are interested in latitude, longitude with the geographic CRS, which is the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see if we can do anything about my comments.
Otherwise it's ok if we merge it but we need to make sure the code stays maintainable and we're not just slapping more if conditionals and booleans into all the places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks so much!
This PR add support for spatials and distance comparisons.
Now you can rund queries like:
or
resolves #11