I’m trying to represent a “query builder” in json forms that represents the following concepts:
- a collection of query groups joined by an operator (And / OR) that contain:
- a collection of queries where each query is joined by an operator (AND / OR) (which I forgot to include in my example below but isn’t a major concern):
- a field to select a
Property name
(an enum of values) - 1 or more fields that are variable based on the selected
Property name
- a field to select a
- a collection of queries where each query is joined by an operator (AND / OR) (which I forgot to include in my example below but isn’t a major concern):
As inspiration, an existing control I have that I’d like to migrate to JSON Forms looks like the following:
By combining the nestedArrays
and conditional-schema-compositions
(examples located in github, links removed due to new user restrictions) examples I think I got pretty much all the pieces together.
Can see the stackblitz example: JSON Forms Query Builder Example - StackBlitz
schema
{ "definitions": { "query": { "type": "object", "properties": { "propertyName": { "type": "string", "enum": ["connectionStatus", "description"] } }, "anyOf": [ { "if": { "properties": { "propertyName": { "const": "connectionStatus" } } }, "then": { "properties": { "connectionStatusOperator": { "type": "string", "enum": ["equals", "doesNotEqual"] }, "connectionStatusValue": { "type": "string", "enum": ["approved", "disconnected", "connected"] } } } }, { "if": { "properties": { "propertyName": { "const": "description" } } }, "then": { "properties": { "descriptionOperator": { "type": "string", "enum": ["equals", "doesNotEqual"] }, "descriptionValue": { "type": "string" } } } } ] }, "queryGroup": { "type": "object", "properties": { "queryGroupsOperator": { "type": "string", "enum": ["AND", "OR"] }, "queries": { "type": "array", "items": { "$ref": "#/definitions/query" } } } } }, "type": "object", "properties": { "queryGroups": { "type": "array", "items": { "$ref": "#/definitions/queryGroup" } } } }
uischema.json
{ "type": "HorizontalLayout", "elements": [ { "type": "Control", "label": { "text": "Query Groups", "show": true }, "scope": "#/properties/queryGroups", "options": { "showSortButtons": true, "detail": { "type": "VerticalLayout", "elements": [ { "type": "Control", "scope": "#/properties/queries", "options": { "showSortButtons": true, "detail": { "type": "HorizontalLayout", "elements": [ { "type": "Control", "scope": "#/properties/propertyName" }, { "type": "Control", "scope": "#/properties/connectionStatusOperator", "rule": { "effect": "SHOW", "condition": { "scope": "#/properties/propertyName", "schema": { "const": "connectionStatus" } } } }, { "type": "Control", "scope": "#/properties/connectionStatusValue", "rule": { "effect": "SHOW", "condition": { "scope": "#/properties/propertyName", "schema": { "const": "connectionStatus" } } } }, { "type": "Control", "scope": "#/properties/descriptionOperator", "rule": { "effect": "SHOW", "condition": { "scope": "#/properties/propertyName", "schema": { "const": "description" } } } }, { "type": "Control", "scope": "#/properties/descriptionValue", "rule": { "effect": "SHOW", "condition": { "scope": "#/properties/propertyName", "schema": { "const": "description" } } } } ] } } }, { "type": "Control", "scope": "#/properties/queryGroupsOperator" } ] } } } ] }
My questions are:
-
Does this look like a reasonable approach to represent the “query builder” pattern? Anyone have alternative examples?
-
The pattern shown is trying to associate a specific
Property Name
configuration with a specific set of additional fields. However the way it is written potentially results in extra fields not associated with the current selectedProperty Name
.For example:
- Select
Property Name
ofconnectionStatus
- Choose a connection status operator
- Switch
Property Name
todescription
- Notice the
connectionStatusOperator
is still in the data:{ "queryGroups": [ { "queries": [ { "propertyName": "description", "connectionStatusOperator": "equals" } ] } ] }
Any ideas on better ways to represent the intended behavior to avoid the unrelated fields in the data for the selected
Property Name
? - Select
-
A limitation of the approach of this pattern is you kind of need to make sure all the possible fields associated with each different
Property Name
configuration are mutually exclusive / globally unique since they all can end up in the same object. In the example I’m prefixing the names with theProperty Name
they are associated with. Any ideas on representing that better / avoiding having to figure out patterns to uniquify the names?