@@ -25,6 +25,20 @@ type Membership @relation(from: "player", to: "team", name: "MEMBER_OF") {
2525 team: Team!
2626 prop: String
2727}
28+
29+ type Category {
30+ name: ID!
31+ parentCategory: Category @relation(name: "HAS_PARENT", direction: OUT, from: "child", to: "parent")
32+ childCategories: [Category!] @relation(name: "HAS_PARENT", direction: IN, from: "parent", to: "child")
33+ parentCategoryAssignment: CategoryAssignment @relation(name: "HAS_PARENT", direction: OUT)
34+ childCategoryAssignments: [CategoryAssignment!] @relation(name: "HAS_PARENT", direction: IN)
35+ }
36+
37+ type CategoryAssignment @relation(from: "child", to: "parent", name: "HAS_PARENT") {
38+ parent: Category!
39+ child: Category!
40+ prop: String
41+ }
2842----
2943
3044== Mutations
@@ -321,3 +335,303 @@ RETURN player {
321335 }]
322336} AS player
323337----
338+
339+ == Recursive bidirectional relations
340+
341+ === Mutation
342+
343+ ==== add incoming relationship
344+
345+ .GraphQL-Query
346+ [source,graphql]
347+ ----
348+ mutation{
349+ addCategoryParentCategory(name: "child", parentCategory: "parent", prop: "foo"){
350+ name
351+ }
352+ }
353+ ----
354+
355+ .Cypher Params
356+ [source,json]
357+ ----
358+ {
359+ "childName":"child",
360+ "parentParentCategory":"parent"
361+ }
362+ ----
363+
364+ .Cypher
365+ [source,cypher]
366+ ----
367+ MATCH (child: Category { name: $childName })
368+ MATCH (parent: Category { name: $parentParentCategory })
369+ MERGE (child)-[: HAS_PARENT]->(parent)
370+ WITH DISTINCT child AS addCategoryParentCategory
371+ RETURN addCategoryParentCategory { .name } AS addCategoryParentCategory
372+ ----
373+
374+ ==== delete incoming relationship
375+
376+ .GraphQL-Query
377+ [source,graphql]
378+ ----
379+ mutation{
380+ deleteCategoryParentCategory(name:"child", parentCategory: "parent") {
381+ name
382+ }
383+ }
384+ ----
385+
386+ .Cypher Params
387+ [source,json]
388+ ----
389+ {
390+ "childName":"child",
391+ "parentParentCategory":"parent"
392+ }
393+ ----
394+
395+ .Cypher
396+ [source,cypher]
397+ ----
398+ MATCH (child: Category { name: $childName })
399+ MATCH (parent: Category { name: $parentParentCategory })
400+ MATCH (child)-[r: HAS_PARENT]->(parent)
401+ DELETE r
402+ WITH DISTINCT child AS deleteCategoryParentCategory
403+ RETURN deleteCategoryParentCategory { .name } AS deleteCategoryParentCategory
404+ ----
405+
406+ ==== add outgoing relationship
407+
408+ .GraphQL-Query
409+ [source,graphql]
410+ ----
411+ mutation{
412+ addCategoryChildCategories(name: "parent", childCategories: ["child1", "child2"], prop: "foo") {
413+ name
414+ }
415+ }
416+ ----
417+
418+ .Cypher Params
419+ [source,json]
420+ ----
421+ {
422+ "parentName" : "parent",
423+ "childChildCategories" : [ "child1", "child2" ]
424+ }
425+ ----
426+
427+ .Cypher
428+ [source,cypher]
429+ ----
430+ MATCH (parent: Category { name: $parentName })
431+ MATCH (child: Category)
432+ WHERE child.name IN $childChildCategories
433+ MERGE (parent)<-[: HAS_PARENT]-(child)
434+ WITH DISTINCT parent AS addCategoryChildCategories
435+ RETURN addCategoryChildCategories { .name } AS addCategoryChildCategories
436+ ----
437+
438+ ==== delete outgoing relationship
439+
440+ .GraphQL-Query
441+ [source,graphql]
442+ ----
443+ mutation{
444+ deleteCategoryChildCategories(name: "parent", childCategories:["child1", "child2"] ) {
445+ name
446+ }
447+ }
448+ ----
449+
450+ .Cypher Params
451+ [source,json]
452+ ----
453+ {
454+ "parentName" : "parent",
455+ "childChildCategories" : [ "child1", "child2" ]
456+ }
457+ ----
458+
459+ .Cypher
460+ [source,cypher]
461+ ----
462+ MATCH (parent: Category { name: $parentName })
463+ MATCH (child: Category) WHERE child.name IN $childChildCategories
464+ MATCH (parent)<-[r: HAS_PARENT]-(child)
465+ DELETE r
466+ WITH DISTINCT parent AS deleteCategoryChildCategories
467+ RETURN deleteCategoryChildCategories { .name } AS deleteCategoryChildCategories
468+ ----
469+
470+ ==== create relationship
471+
472+ .GraphQL-Query
473+ [source,graphql]
474+ ----
475+ mutation{
476+ createCategoryAssignment(parent_name: "parent", child_name: "child", prop: "foo"){
477+ prop
478+ }
479+ }
480+ ----
481+
482+ .Cypher Params
483+ [source,json]
484+ ----
485+ {
486+ "childChild_name" : "child",
487+ "parentParent_name" : "parent",
488+ "createCategoryAssignmentProp" : "foo"
489+ }
490+ ----
491+
492+ .Cypher
493+ [source,cypher]
494+ ----
495+ MATCH (child: Category { name: $childChild_name })
496+ MATCH (parent: Category { name: $parentParent_name })
497+ CREATE (child)-[createCategoryAssignment: HAS_PARENT { prop: $createCategoryAssignmentProp }]->(parent)
498+ WITH createCategoryAssignment
499+ RETURN createCategoryAssignment { .prop } AS createCategoryAssignment
500+ ----
501+
502+ === Queries
503+
504+ ==== query incoming node
505+
506+ .GraphQL-Query
507+ [source,graphql]
508+ ----
509+ {
510+ category{
511+ name
512+ childCategories{name}
513+ }
514+ }
515+ ----
516+
517+ .Cypher Params
518+ [source,json]
519+ ----
520+ {}
521+ ----
522+
523+ .Cypher
524+ [source,cypher]
525+ ----
526+ MATCH (category: Category)
527+ RETURN category {
528+ .name,
529+ childCategories: [(category)<-[: HAS_PARENT]-(categoryChildCategories: Category) | categoryChildCategories {
530+ .name
531+ }]
532+ } AS category
533+ ----
534+
535+ ==== query outgoing node
536+
537+ .GraphQL-Query
538+ [source,graphql]
539+ ----
540+ {
541+ category{
542+ name
543+ parentCategory{name}
544+ }
545+ }
546+ ----
547+
548+ .Cypher Params
549+ [source,json]
550+ ----
551+ {}
552+ ----
553+
554+ .Cypher
555+ [source,cypher]
556+ ----
557+ MATCH (category: Category)
558+ RETURN category {
559+ .name,
560+ parentCategory: [(category)-[: HAS_PARENT]->(categoryParentCategory: Category) | categoryParentCategory {
561+ .name
562+ }][0]
563+ } AS category
564+ ----
565+
566+ ==== query incoming relation
567+
568+ .GraphQL-Query
569+ [source,graphql]
570+ ----
571+ {
572+ category{
573+ name
574+ childCategoryAssignments{
575+ child {name}
576+ prop
577+ }
578+ }
579+ }
580+ ----
581+
582+ .Cypher Params
583+ [source,json]
584+ ----
585+ {}
586+ ----
587+
588+ .Cypher
589+ [source,cypher]
590+ ----
591+ MATCH (category: Category)
592+ RETURN category {
593+ .name,
594+ childCategoryAssignments: [(category)<-[categoryChildCategoryAssignments: HAS_PARENT]-(categoryChildCategoryAssignmentsChild: Category) | categoryChildCategoryAssignments {
595+ child: categoryChildCategoryAssignmentsChild {
596+ .name
597+ },
598+ .prop
599+ }] } AS category
600+ ----
601+
602+ ==== query outgoing relation
603+
604+ .GraphQL-Query
605+ [source,graphql]
606+ ----
607+ {
608+ category {
609+ name
610+ parentCategoryAssignment {
611+ parent {name}
612+ prop
613+ }
614+ }
615+ }
616+ ----
617+
618+ .Cypher Params
619+ [source,json]
620+ ----
621+ {}
622+ ----
623+
624+ .Cypher
625+ [source,cypher]
626+ ----
627+ MATCH (category: Category)
628+ RETURN category {
629+ .name,
630+ parentCategoryAssignment: [(category)-[categoryParentCategoryAssignment: HAS_PARENT]->(categoryParentCategoryAssignmentParent: Category) | categoryParentCategoryAssignment {
631+ parent: categoryParentCategoryAssignmentParent {
632+ .name
633+ },
634+ .prop
635+ }][0]
636+ } AS category
637+ ----
0 commit comments