Skip to content

Routing, MK2

Samiwel Thomas edited this page Jan 7, 2019 · 17 revisions

Update 14.11.2018

@samiwel, @SamGodwin2 and @jonnyshaw89 met to discuss. We think this schema will meet all of our known routing requirements going forward but there are a few questions we had surrounding how the expansion of routing rules will look in publisher that are probably worth considering separately.


It's recently come up that out current implementation of routing may not include enough complexity for our purposes meaning that it's time to make routing great again.

The new schema is designed to allow for more complex logic, more answer types, and even metadata. The schema below aims to allow for all these things while also making sure the front end receives the complex boolean logic in a simple way.

union ValueUnion = OptionIdArray | Custom | Answer | Metadata

union RoutingUnion = RoutingRule | RoutingRuleSet

union SubjectUnion = Answer | Metadata

enum OperatorEnum {
  Equal
  Not Equal
  Greater Than
  Less Than
  Greater|Equal
  Less|Equal
  Contains All
  Contains Some 
  Contains None
}

enum ConditionEnum {
  AND
  OR
}

enum RoutingRuleSetParent {
  RoutingPage
  RoutingRuleSet
}

type OptionIdArray {
    options: [Option]
}

type RoutingPage {
	routingRuleSets: [RoutingRuleSet]
	fallThroughDestination: Destination
}

type RoutingRuleSet {
    condition: ConditionEnum
    rules: [RoutingUnion]
	destination: Destination
}

type RoutingRule {
    id: ID!
    leftHandSide: SubjectUnion
    operator: OperatorEnum
    rightHandSide: ValueUnion
  }

input CreateRoutingRule {
  parentRoutingRuleSet: ID!
}

input UpdateRoutingRule {
  id: ID!
  leftHandSide: LeftHandSideInput
  operator: OperatorEnum
  rightHandSide: RightHAndSideInput
}

input LeftHandSideInput {
  answerId: ID!
  metadataId: ID!
}

input RightHandSideInput {
  answerId: ID
  metadataId: ID
  optionIdArray: [ID]
  customNumber: Int
  customDate: Date
}

input DeleteRoutingRule {
  id: ID!
}

input CreateRoutingRuleSet {
  parentType: RoutingRuleSetParent!
  parentId: ID! 
}

input DeleteRoutingRuleSet{
  id: ID!

This schema should hopefully allow the front end to receive a array which will be a combination of rules and rule sets. Each of the rule sets will allow further rules to be nested within them allowing for the complex nested queries we're looking for.

For example the rough structure of the returned data might be as follows:

{
	condition: AND
	rules: [
	{
		...RoutingRule
	},
	{
		...RoutingRule
	},
	{
		condition: OR,
		rules: [
		{
			...RoutingRule
		},
		{
			...RoutingRule
		} 		
		]
	}
	]
}

The idea being that the structure could go as deep as we'd like it to go.

The Query to retrieve this this data should hopefully look something like this:

Query RoutingRule (id: input){
	RoutingRuleSet{
		condition
		rules {
			... on RoutingRule {
				leftHandSide
				operator
				rightHandSide
			}
			... on RoutingRuleSet {
				condition
				rules {
					... on RoutingRule {
					leftHandSide
					operator
					rightHandSide
					}
					... on RoutingRuleSet {
						condition
						rules {
							... on RoutingRule {
							leftHandSide
							operator
							rightHandSide
							}
						}
					}
				}
			}
		}
	}

For the new database structure there would need to be another revamp:

Top

RoutigPageTable:

id Pageid destination
1 FK FK

RoutingRuleSetTable:

id Parent type ParentId comparator destination
1 enum FK AND or OR FK

RoutingRuleTable

id Parent Id LeftHandSideTable RightHandSideTable Operator
1 FK FK FK = or > ect...

LeftHandSideTable (SubjectTable)

id AnswerId Metadata Id
1 FK FK

RightHandSideTable (ValueTable)

id AnswerId Metadata Id Custom selectedType
1 FK FK JSON FK

Option Table

id optionId RightHandSideTable id
1 FK FK

For the rule (answer1 = optionNo || unanswered) and answer2 != 8 and answer3=optionYes the following patten would emerge:

{
	condition: AND
	rules: [
	{
		condition: OR,
		rules: [
		{
			lhs: answer1
			comparator:Equal
			rhs:option2
		},
		{
			lhs: answer1
			comparator:Not Set
			rhs:null
		} 		
		]
	},
	{
		lhs: answer2
		comparator:NotEqual
		rhs:option8
	},
	{
		lhs: answer3
		comparator:Equal
		rhs:option1
	}
	]
}

The runner schema for this same condition currently looks like

[
  {
    goto: destination,
    when: [
      {
        condition: "not set",
        id: answer1
      },
      {
        condition: "not equals",
        id: answer2,
        value: 8
      },
      {
        condition: "not equals",
        id: answer3,
        value: option1
      }
    ]
  },
  {
    goto: destination,
    when: [
      {
        condition: "equals",
        id: answer1,
        value: option2
      },
      {
        condition: "not equals",
        id: answer2,
        value: 8
      },
      {
        condition: "not equals",
        id: answer3,
        value: option1
      }
    ]
  }
];
Clone this wiki locally