Skip to content

Commit

Permalink
update dependencies (#302)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy2003 authored Apr 9, 2024
1 parent 97aee0d commit e5a9dac
Show file tree
Hide file tree
Showing 28 changed files with 287 additions and 241 deletions.
20 changes: 10 additions & 10 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>5.3.1</version>
<version>5.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -45,10 +45,15 @@
<version>${neo4j-apoc.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-dsl</artifactId>
<version>2023.9.5</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>19.2</version>
<version>21.5</version>
</dependency>
<dependency>
<groupId>org.atteo</groupId>
Expand All @@ -70,11 +75,6 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-dsl</artifactId>
<version>2023.0.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
Expand All @@ -91,7 +91,7 @@
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.9.0</version>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -111,12 +111,12 @@
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.23.1</version>
<version>3.24.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.5</version>
<version>2.0.7</version>
</dependency>
</dependencies>
</dependencyManagement>
Expand Down
18 changes: 13 additions & 5 deletions core/src/main/kotlin/org/neo4j/graphql/DynamicProperties.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
package org.neo4j.graphql

import graphql.Assert
import graphql.GraphQLContext
import graphql.execution.CoercedVariables
import graphql.language.*
import graphql.schema.*
import java.util.*

object DynamicProperties {

val INSTANCE: GraphQLScalarType = GraphQLScalarType.newScalar()
.name("DynamicProperties")
.coercing(object : Coercing<Any, Any> {
@Throws(CoercingSerializeException::class)
override fun serialize(input: Any): Any {
override fun serialize(input: Any, graphQLContext: GraphQLContext, locale: Locale): Any {
return input
}

@Throws(CoercingParseValueException::class)
override fun parseValue(input: Any): Any {
@Throws(CoercingParseLiteralException::class)
override fun parseValue(input: Any, graphQLContext: GraphQLContext, locale: Locale): Any {
return input
}

@Throws(CoercingParseLiteralException::class)
override fun parseLiteral(o: Any): Any {
return parse(o, emptyMap())
override fun parseLiteral(
input: Value<*>,
variables: CoercedVariables,
graphQLContext: GraphQLContext,
locale: Locale
): Any {
return parse(input, emptyMap())
}
})
.build()
Expand Down
10 changes: 6 additions & 4 deletions core/src/main/kotlin/org/neo4j/graphql/ExtensionFunctions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@ import graphql.language.Description
import graphql.language.VariableReference
import graphql.schema.GraphQLOutputType
import org.neo4j.cypherdsl.core.*
import org.neo4j.cypherdsl.core.Cypher
import org.neo4j.cypherdsl.core.Cypher.elementId
import java.util.*

fun queryParameter(value: Any?, vararg parts: String?): Parameter<*> {
val name = when (value) {
is VariableReference -> value.name
else -> normalizeName(*parts)
}
return org.neo4j.cypherdsl.core.Cypher.parameter(name).withValue(value?.toJavaValue())
return Cypher.parameter(name).withValue(value?.toJavaValue())
}

fun Expression.collect(type: GraphQLOutputType) = if (type.isList()) Functions.collect(this) else this
fun Expression.collect(type: GraphQLOutputType) = if (type.isList()) Cypher.collect(this) else this
fun StatementBuilder.OngoingReading.withSubQueries(subQueries: List<Statement>) = subQueries.fold(this, { it, sub -> it.call(sub) })

fun normalizeName(vararg parts: String?) = parts.mapNotNull { it?.capitalize() }.filter { it.isNotBlank() }.joinToString("").decapitalize()

fun PropertyContainer.id(): FunctionInvocation = when (this) {
is Node -> Functions.id(this)
is Relationship -> Functions.id(this)
is Node -> elementId(this)
is Relationship -> elementId(this)
else -> throw IllegalArgumentException("Id can only be retrieved for Nodes or Relationships")
}

Expand Down
21 changes: 10 additions & 11 deletions core/src/main/kotlin/org/neo4j/graphql/GraphQLExtensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fun GraphQLFieldDefinition.isNeo4jTemporalType(): Boolean = this.type.isNeo4jTem

fun GraphQLFieldDefinition.isRelationship() = !type.isNeo4jType() && this.type.inner().let { it is GraphQLFieldsContainer }

fun GraphQLFieldsContainer.isRelationType() = (this as? GraphQLDirectiveContainer)?.getDirective(DirectiveConstants.RELATION) != null
fun GraphQLFieldsContainer.isRelationType() = (this as? GraphQLDirectiveContainer)?.getAppliedDirective(DirectiveConstants.RELATION) != null
fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo<GraphQLFieldsContainer>? {
val field = getRelevantFieldDefinition(name)
?: throw IllegalArgumentException("$name is not defined on ${this.name}")
Expand All @@ -61,15 +61,15 @@ fun GraphQLFieldsContainer.relationshipFor(name: String): RelationshipInfo<Graph
val (relDirective, inverse) = if (isRelationType()) {
val typeName = this.name
(this as? GraphQLDirectiveContainer)
?.getDirective(DirectiveConstants.RELATION)?.let {
?.getAppliedDirective(DirectiveConstants.RELATION)?.let {
// do inverse mapping, if the current type is the `to` mapping of the relation
it to (fieldObjectType.getRelevantFieldDefinition(it.getArgument(RELATION_TO, null as String?))?.name == typeName)
}
?: throw IllegalStateException("Type ${this.name} needs an @relation directive")
} else {
(fieldObjectType as? GraphQLDirectiveContainer)
?.getDirective(DirectiveConstants.RELATION)?.let { it to true }
?: field.getDirective(DirectiveConstants.RELATION)?.let { it to false }
?.getAppliedDirective(DirectiveConstants.RELATION)?.let { it to true }
?: field.getAppliedDirective(DirectiveConstants.RELATION)?.let { it to false }
?: throw IllegalStateException("Field $field needs an @relation directive")
}

Expand All @@ -92,7 +92,7 @@ fun GraphQLFieldsContainer.getValidTypeLabels(schema: GraphQLSchema): List<Strin
fun GraphQLFieldsContainer.label(): String = when {
this.isRelationType() ->
(this as? GraphQLDirectiveContainer)
?.getDirective(DirectiveConstants.RELATION)
?.getAppliedDirective(DirectiveConstants.RELATION)
?.getArgument(RELATION_NAME)?.argumentValue?.value?.toJavaValue()?.toString()
?: this.name

Expand Down Expand Up @@ -125,7 +125,7 @@ fun GraphQLType.getInnerFieldsContainer() = inner() as? GraphQLFieldsContainer
?: throw IllegalArgumentException("${this.innerName()} is neither an object nor an interface")

fun <T> GraphQLDirectiveContainer.getDirectiveArgument(directiveName: String, argumentName: String, defaultValue: T?): T? =
getDirective(directiveName)?.getArgument(argumentName, defaultValue) ?: defaultValue
getAppliedDirective(directiveName)?.getArgument(argumentName, defaultValue) ?: defaultValue

@Suppress("UNCHECKED_CAST")
fun <T> DirectivesContainer<*>.getDirectiveArgument(typeRegistry: TypeDefinitionRegistry, directiveName: String, argumentName: String, defaultValue: T? = null): T? {
Expand All @@ -141,25 +141,24 @@ fun <T> DirectivesContainer<*>.getDirectiveArgument(typeRegistry: TypeDefinition

fun DirectivesContainer<*>.getDirective(name: String): Directive? = directives.firstOrNull { it.name == name }

@Suppress("UNCHECKED_CAST")
fun <T> DirectivesContainer<*>.getMandatoryDirectiveArgument(typeRegistry: TypeDefinitionRegistry, directiveName: String, argumentName: String, defaultValue: T? = null): T =
getDirectiveArgument(typeRegistry, directiveName, argumentName, defaultValue)
?: throw IllegalStateException("No default value for @${directiveName}::$argumentName")

fun <T> GraphQLDirective.getMandatoryArgument(argumentName: String, defaultValue: T? = null): T = this.getArgument(argumentName, defaultValue)
fun <T> GraphQLAppliedDirective.getMandatoryArgument(argumentName: String, defaultValue: T? = null): T = this.getArgument(argumentName, defaultValue)
?: throw IllegalStateException(argumentName + " is required for @${this.name}")

fun <T> GraphQLDirective.getArgument(argumentName: String, defaultValue: T? = null): T? {
fun <T> GraphQLAppliedDirective.getArgument(argumentName: String, defaultValue: T? = null): T? {
val argument = getArgument(argumentName)
@Suppress("UNCHECKED_CAST")
return when {
argument.argumentValue.isSet && argument.argumentValue.value != null -> argument.argumentValue.value?.toJavaValue() as T?
argument.argumentDefaultValue.isSet -> argument.argumentDefaultValue.value?.toJavaValue() as T?
argument.definition?.value != null -> argument.definition?.value?.toJavaValue() as T?
else -> defaultValue ?: throw IllegalStateException("No default value for @${this.name}::$argumentName")
}
}

fun GraphQLFieldDefinition.cypherDirective(): CypherDirective? = getDirective(CYPHER)?.let {
fun GraphQLFieldDefinition.cypherDirective(): CypherDirective? = getAppliedDirective(CYPHER)?.let {
val originalStatement = it.getMandatoryArgument<String>(CYPHER_STATEMENT)
// Arguments on the field are passed to the Cypher statement and can be used by name.
// They must not be prefixed by $ since they are no longer parameters. Just use the same name as the fields' argument.
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/kotlin/org/neo4j/graphql/Neo4jTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ class Neo4jTimeConverter(name: String) : Neo4jConverter(name) {
class Neo4jPointConverter(name: String) : Neo4jConverter(name) {

fun createDistanceCondition(lhs: Expression, rhs: Parameter<*>, conditionCreator: (Expression, Expression) -> Condition): Condition {
val point = Functions.point(rhs.property("point"))
val point = Cypher.point(rhs.property("point"))
val distance = rhs.property("distance")
return conditionCreator(Functions.distance(lhs, point), distance)
return conditionCreator(Cypher.distance(lhs, point), distance)
}
}

Expand Down
22 changes: 10 additions & 12 deletions core/src/main/kotlin/org/neo4j/graphql/Predicates.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import graphql.language.TypeDefinition
import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLFieldsContainer
import org.neo4j.cypherdsl.core.*
import org.neo4j.cypherdsl.core.Predicates.OngoingListBasedPredicateFunction
import org.neo4j.cypherdsl.core.Cypher
import org.slf4j.LoggerFactory

typealias CypherDSL = org.neo4j.cypherdsl.core.Cypher

private fun createArrayPredicate(factory: (SymbolicName) -> OngoingListBasedPredicateFunction) = { lhs: Expression, rhs: Expression ->
val x: SymbolicName = org.neo4j.cypherdsl.core.Cypher.name("x")
private fun createArrayPredicate(factory: (SymbolicName) -> Predicates.OngoingListBasedPredicateFunction) = { lhs: Expression, rhs: Expression ->
val x: SymbolicName = Cypher.name("x")
factory(x).`in`(lhs).where(x.`in`(rhs))
}

Expand Down Expand Up @@ -42,10 +40,10 @@ enum class FieldOperator(
EW("_ends_with", { lhs, rhs -> lhs.endsWith(rhs) }),
MATCHES("_matches", { lhs, rhs -> lhs.matches(rhs) }),

INCLUDES_ALL("_includes_all", createArrayPredicate(Predicates::all), list = true),
INCLUDES_SOME("_includes_some", createArrayPredicate(Predicates::any), list = true),
INCLUDES_NONE("_includes_none", createArrayPredicate(Predicates::none), list = true),
INCLUDES_SINGLE("_includes_single", createArrayPredicate(Predicates::single), list = true),
INCLUDES_ALL("_includes_all", createArrayPredicate(Cypher::all), list = true),
INCLUDES_SOME("_includes_some", createArrayPredicate(Cypher::any), list = true),
INCLUDES_NONE("_includes_none", createArrayPredicate(Cypher::none), list = true),
INCLUDES_SINGLE("_includes_single", createArrayPredicate(Cypher::single), list = true),

DISTANCE(NEO4j_POINT_DISTANCE_FILTER_SUFFIX, { lhs, rhs -> lhs.isEqualTo(rhs) }, distance = true),
DISTANCE_LT(NEO4j_POINT_DISTANCE_FILTER_SUFFIX + "_lt", { lhs, rhs -> lhs.lt(rhs) }, distance = true),
Expand Down Expand Up @@ -74,10 +72,10 @@ enum class FieldOperator(
val id = propertyContainer.id()
val parameter = queryParameter(value, variablePrefix, queriedField, suffix)
val condition = if (list) {
val idVar = CypherDSL.name("id")
conditionCreator(id, CypherDSL.listWith(idVar).`in`(parameter).returning(CypherDSL.call("toInteger").withArgs(idVar).asFunction()))
val idVar = Cypher.name("id")
conditionCreator(id, Cypher.listWith(idVar).`in`(parameter).returning(idVar))
} else {
conditionCreator(id, CypherDSL.call("toInteger").withArgs(parameter).asFunction())
conditionCreator(id, parameter)
}
listOf(condition)
} else {
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/kotlin/org/neo4j/graphql/RelationshipInfo.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.neo4j.graphql

import graphql.language.ImplementingTypeDefinition
import graphql.schema.GraphQLDirective
import graphql.schema.GraphQLAppliedDirective
import graphql.schema.GraphQLDirectiveContainer
import graphql.schema.GraphQLFieldsContainer
import graphql.schema.idl.TypeDefinitionRegistry
Expand Down Expand Up @@ -33,10 +33,10 @@ data class RelationshipInfo<TYPE>(

companion object {
fun create(type: GraphQLFieldsContainer): RelationshipInfo<GraphQLFieldsContainer>? = (type as? GraphQLDirectiveContainer)
?.getDirective(DirectiveConstants.RELATION)
?.getAppliedDirective(DirectiveConstants.RELATION)
?.let { relDirective -> create(type, relDirective) }

fun create(type: GraphQLFieldsContainer, relDirective: GraphQLDirective): RelationshipInfo<GraphQLFieldsContainer> {
fun create(type: GraphQLFieldsContainer, relDirective: GraphQLAppliedDirective): RelationshipInfo<GraphQLFieldsContainer> {
val relType = relDirective.getArgument(DirectiveConstants.RELATION_NAME, "")!!
val direction = relDirective.getArgument<String>(DirectiveConstants.RELATION_DIRECTION, null)
?.let { RelationDirection.valueOf(it) }
Expand Down
17 changes: 16 additions & 1 deletion core/src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class SchemaBuilder(
when (typeDefinition) {
is ImplementingTypeDefinition -> typeDefinition.fieldDefinitions
.flatMap { fieldDefinition -> fieldDefinition.inputValueDefinitions.map { it.type } + fieldDefinition.type }

is InputObjectTypeDefinition -> typeDefinition.inputValueDefinitions.map { it.type }
else -> emptyList()
}
Expand All @@ -141,6 +142,20 @@ class SchemaBuilder(
.filterNot { typeDefinitionRegistry.hasType(it) }
.mapNotNull { neo4jTypeDefinitionRegistry.getType(it).unwrap() }
.forEach { typeDefinitionRegistry.add(it) }


if (typeDefinitionRegistry.getType(mutationTypeName).isPresent) {
typeDefinitionRegistry.schemaDefinition().ifPresent { schemaDefinition ->
typeDefinitionRegistry.remove(schemaDefinition)
typeDefinitionRegistry.add(schemaDefinition.transform {
val ops = schemaDefinition.operationTypeDefinitions.toMutableList()
if (ops.find { it.name == "mutation" } == null) {
ops.add(OperationTypeDefinition("mutation", TypeName(mutationTypeName)))
}
it.operationTypeDefinitions(ops)
})
}
}
}

/**
Expand Down Expand Up @@ -282,7 +297,7 @@ class SchemaBuilder(
override fun get(env: DataFetchingEnvironment): Any? {
val source = env.getSource<Any>() ?: return null
val propertyName = env.mergedField.singleField.alias ?: env.mergedField.singleField.name
return PropertyDataFetcherHelper.getPropertyValue(propertyName, source, env.fieldType, env)
return PropertyDataFetcherHelper.getPropertyValue(propertyName, source, env.fieldType, { env })
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ abstract class BaseDataFetcher(schemaConfig: SchemaConfig) : ProjectionBase(sche
.build()
).render(statement)

val params = statement.parameters.mapValues { (_, value) ->
val params = statement.catalog.parameters.mapValues { (_, value) ->
(value as? VariableReference)?.let { env.variables[it.name] } ?: value
}
return Cypher(query, params, env.fieldDefinition.type, variable = field.aliasOrName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import graphql.language.ArrayValue
import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLFieldsContainer
import graphql.schema.GraphQLType
import org.neo4j.cypherdsl.core.*
import org.neo4j.cypherdsl.core.Condition
import org.neo4j.cypherdsl.core.Cypher.*
import org.neo4j.cypherdsl.core.Expression
import org.neo4j.cypherdsl.core.PropertyContainer
import org.neo4j.graphql.*

/**
Expand Down Expand Up @@ -96,19 +98,19 @@ abstract class BaseDataFetcherForContainer(schemaConfig: SchemaConfig) : BaseDat
val (propContainer, func) = if (isRelation) {
val variableName = name(variable)
val rel = anyNode().relationshipTo(anyNode(), label).named(variableName)
rel to Functions.id(rel)
rel to elementId(rel)
} else {
val node = node(label).named(variable)
node to Functions.id(node)
node to elementId(node)
}
val where = func.isEqualTo(call("toInteger").withArgs(idParam).asFunction())
val where = func.isEqualTo(idParam)
propContainer to where
} else {
val node = node(label).named(variable)
if (idProperty.value is ArrayValue) {
node to node.property(idField.propertyName()).`in`(idParam)
} else {
node.withProperties(idField.propertyName(), idParam) to Conditions.noCondition()
node.withProperties(idField.propertyName(), idParam) to noCondition()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,13 @@ class OptimizedFilterHandler(val type: GraphQLFieldsContainer, schemaConfig: Sch
private fun totalFilter(relationPredicate: RelationPredicate, relVariableName: String): Pair<SymbolicName, AliasedExpression> {
val totalRel = relationPredicate.relationshipInfo.createRelation(currentNode(), relationPredicate.relNode)
val totalVar = normalizeName(relVariableName, "Total")
val total = Functions.size(totalRel).`as`(totalVar)
val total = Cypher.size(totalRel).`as`(totalVar)
return Cypher.name(totalVar) to total
}

private fun countFilter(relVariable: Node, relVariableName: String): Pair<SymbolicName, AliasedExpression> {
val countVar = normalizeName(relVariableName, "Count")
val count = Functions.countDistinct(relVariable).`as`(countVar)
val count = Cypher.countDistinct(relVariable).`as`(countVar)
return Cypher.name(countVar) to count
}

Expand Down
Loading

0 comments on commit e5a9dac

Please sign in to comment.