diff --git a/src/main/kotlin/org/sirius/dorm/graphql/GraphQLProvider.kt b/src/main/kotlin/org/sirius/dorm/graphql/GraphQLProvider.kt index 8710dc4..5e394eb 100644 --- a/src/main/kotlin/org/sirius/dorm/graphql/GraphQLProvider.kt +++ b/src/main/kotlin/org/sirius/dorm/graphql/GraphQLProvider.kt @@ -57,6 +57,7 @@ class GraphQLProvider { fun setup() { graphQL= GraphQL.newGraphQL(withTransaction { SchemaBuilder(objectManager).createSchema() }) .queryExecutionStrategy(TransactionalExecutionStrategy(objectManager, SimpleDataFetcherExceptionHandler())) + .mutationExecutionStrategy(TransactionalExecutionStrategy(objectManager, SimpleDataFetcherExceptionHandler())) .build() queryBuilder = QueryBuilder(objectManager) diff --git a/src/main/kotlin/org/sirius/dorm/graphql/ObjectMutator.kt b/src/main/kotlin/org/sirius/dorm/graphql/ObjectMutator.kt new file mode 100644 index 0000000..3d28b9f --- /dev/null +++ b/src/main/kotlin/org/sirius/dorm/graphql/ObjectMutator.kt @@ -0,0 +1,63 @@ +package org.sirius.dorm.graphql +/* + * @COPYRIGHT (C) 2023 Andreas Ernst + * + * All rights reserved + */ + +import org.sirius.dorm.ObjectManager +import org.sirius.dorm.model.AttributeDescriptor +import org.sirius.dorm.model.ObjectDescriptor +import org.sirius.dorm.model.PropertyDescriptor +import org.sirius.dorm.`object`.DataObject + + +class ObjectMutator(val objectManager: ObjectManager) { + // update + + fun update(descriptor: ObjectDescriptor, input: Map) : DataObject { + val obj = objectManager.findById(descriptor, (input.get("id") as Number).toLong())!! + + // iterate over properties + + for ( key in input.keys) { + if (key == "id") + continue + + val property = descriptor.property(key) + + if ( property.isAttribute()) + obj[key] = coerce(input[key]!!, property.asAttribute()) + } + + return obj + } + + private fun coerce(value: Any, property: AttributeDescriptor<*>): Any { + if ( !property.type.baseType.isAssignableFrom( value.javaClass)) { + println("?") + } + + return value + } + + // create + + fun create(descriptor: ObjectDescriptor, input: Map) : DataObject { + val newObject = objectManager.create(descriptor) + + // iterate over properties + + for ( key in input.keys) { + if (key == "id") + continue + + val property = descriptor.property(key) + + if ( property.isAttribute()) + newObject[key] = coerce(input[key]!!, property.asAttribute()) + } + + return newObject + } +} \ No newline at end of file diff --git a/src/main/kotlin/org/sirius/dorm/graphql/SchemaBuilder.kt b/src/main/kotlin/org/sirius/dorm/graphql/SchemaBuilder.kt index 0b37a47..662b55d 100644 --- a/src/main/kotlin/org/sirius/dorm/graphql/SchemaBuilder.kt +++ b/src/main/kotlin/org/sirius/dorm/graphql/SchemaBuilder.kt @@ -14,6 +14,7 @@ import org.sirius.dorm.`object`.DataObject class SchemaBuilder(val objectManager: ObjectManager) { private val queryBuilder = QueryBuilder(objectManager) + private val mutator = ObjectMutator(objectManager) // public @@ -28,6 +29,8 @@ class SchemaBuilder(val objectManager: ObjectManager) { // iterate over object definitions for ( descriptor in objectManager.descriptors()) { + // create the type itself + val newObject = GraphQLObjectType.newObject().name(descriptor.name) for ( field in descriptor.properties) { @@ -62,10 +65,41 @@ class SchemaBuilder(val objectManager: ObjectManager) { ) } } - } // for + } // for property types.add(newObject.build()) - } + + // input object + + val inputObject = GraphQLInputObjectType.newInputObject().name("${descriptor.name}Input") + + for ( field in descriptor.properties) { + if ( field.isAttribute()) + inputObject.field( + GraphQLInputObjectField.newInputObjectField() + .name(field.name) + .type(inputType4(field.asAttribute().baseType())) + ) + /* TODO else { + if ( field.asRelation().multiplicity.mutliValued) { + inputObject.field( + GraphQLFieldDefinition.newFieldDefinition() + .name(field.name) + .type(GraphQLList.list((GraphQLTypeReference.typeRef(field.asRelation().target)))) + ) + } + else { + inputObject.field( + GraphQLFieldDefinition.newFieldDefinition() + .name(field.name) + .type(GraphQLTypeReference.typeRef(field.asRelation().target)) + ) + } + }*/ + } // for property + + types.add(inputObject.build()) + } // for descriptor // query @@ -123,16 +157,48 @@ class SchemaBuilder(val objectManager: ObjectManager) { } .type(GraphQLList.list(GraphQLTypeReference.typeRef(descriptor.name))) ) - } + } // for + + // mutation + + val mutation = GraphQLObjectType.newObject().name("Mutation") + + for ( descriptor in objectManager.descriptors()) { + // create + + mutation.field( + GraphQLFieldDefinition.newFieldDefinition() + .name("create${descriptor.name}") + .argument(GraphQLArgument.newArgument().name("input").type(GraphQLTypeReference.typeRef(descriptor.name + "Input")).build()) + .dataFetcher { + executeCreate(descriptor, it) + } + .type(GraphQLTypeReference.typeRef(descriptor.name)) + ) + + // update + + mutation.field( + GraphQLFieldDefinition.newFieldDefinition() + .name("update${descriptor.name}") + .argument(GraphQLArgument.newArgument().name("input").type(GraphQLTypeReference.typeRef("${descriptor.name}Input")).build()) + .dataFetcher { + executeUpdate(descriptor, it) + } + .type(GraphQLTypeReference.typeRef(descriptor.name)) + ) + } // for + + // create schema val schema = GraphQLSchema.newSchema() .query(query.build()) + .mutation(mutation.build()) .additionalTypes(types) .build() println(SchemaPrinter().print(schema)) - return schema } @@ -142,6 +208,14 @@ class SchemaBuilder(val objectManager: ObjectManager) { return queryBuilder.buildQuery(descriptor, environment.getArgument("filter")).execute().getResultList() } + private fun executeCreate(descriptor: ObjectDescriptor, environment: DataFetchingEnvironment) : DataObject { + return mutator.create(descriptor, environment.getArgument("input") as Map) + } + + private fun executeUpdate(descriptor: ObjectDescriptor, environment: DataFetchingEnvironment) : DataObject { + return mutator.update(descriptor, environment.getArgument("input") as Map) + } + private fun stringFilter() : GraphQLInputObjectType { return GraphQLInputObjectType.newInputObject() .name("StringFilter") @@ -194,7 +268,7 @@ class SchemaBuilder(val objectManager: ObjectManager) { .build() } - private fun type4(clazz : Class<*>) : GraphQLOutputType { + private fun inputType4(clazz : Class<*>) : GraphQLInputType { return when ( clazz ) { Boolean::class.javaObjectType -> Scalars.GraphQLBoolean Int::class.javaObjectType -> Scalars.GraphQLInt @@ -209,4 +283,18 @@ class SchemaBuilder(val objectManager: ObjectManager) { } } + private fun type4(clazz : Class<*>) : GraphQLOutputType { + return when ( clazz ) { + Boolean::class.javaObjectType -> Scalars.GraphQLBoolean + Int::class.javaObjectType -> Scalars.GraphQLInt + Short::class.javaObjectType -> Scalars.GraphQLInt + Long::class.javaObjectType -> Scalars.GraphQLInt + Float::class.javaObjectType -> Scalars.GraphQLFloat + Double::class.javaObjectType -> Scalars.GraphQLFloat + String::class.javaObjectType -> Scalars.GraphQLString + else -> { + throw Error("unsupported type ${clazz}") + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/org/sirius/dorm/graphql/TODO-GRAPHQL.TXT b/src/main/kotlin/org/sirius/dorm/graphql/TODO-GRAPHQL.TXT index 5e508d7..00de5cd 100644 --- a/src/main/kotlin/org/sirius/dorm/graphql/TODO-GRAPHQL.TXT +++ b/src/main/kotlin/org/sirius/dorm/graphql/TODO-GRAPHQL.TXT @@ -5,7 +5,6 @@ - mutation update-person delete-person - - applikation - maven submodule - admin service ausplitten + finalisieren @@ -13,17 +12,15 @@ === LATER -=== NOW - -- Browser Test? +angular :-) mit builder simple -=== QUERY - - at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.28.jar:10.1.28] +=== NOW +- create-person === DONE +- postman test - restliche prädikate - Spring einbinden - überlegen syntax select?