diff --git a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx index 03f75e7f9f004b9a4e91d5219393037624fb2fe1..fb0fcb6a919311c900b1ba40e13b5cac290330d6 100644 --- a/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx +++ b/apps/web/src/components/navbar/DatabaseManagement/forms/settings.tsx @@ -166,29 +166,43 @@ export const SettingsForm = (props: { onClose(): void; open: 'add' | 'update'; s </div> )} - <div - className={`grid md:grid-cols-2 gap-3 card-actions w-full justify-stretch items-center ${sampleDataPanel === true && 'hidden'}`} - > - <Button - type="primary" - label={connection.updating ? (formTitle === 'Add' ? formTitle + 'ing...' : formTitle.slice(0, -1) + 'ing...') : formTitle} - onClick={(event) => { - event.preventDefault(); - handleSubmit(); - }} - disabled={connection.updating || hasError} - /> - <Button - variant="outline" - label="Cancel" - disabled={props.disableCancel} - onClick={(event) => { - event.preventDefault(); - closeDialog(); - }} - /> - </div> - </> + <div + className={`pt-4 flex flex-row gap-3 card-actions w-full justify-stretch items-center ${sampleDataPanel === true && 'hidden'}`} + > + <Button + variantType="primary" + className="flex-grow" + label={connection.updating ? (formTitle === 'Add' ? formTitle + 'ing...' : formTitle.slice(0, -1) + 'ing...') : formTitle} + onClick={(event) => { + event.preventDefault(); + handleSubmit(); + }} + disabled={connection.updating || hasError} + /> + {props.open === 'update' && ( + <Button + variantType="secondary" + className="flex-grow" + label={'Clone'} + onClick={(event) => { + handleSubmit({ ...formData, name: formData.name + ' (copy)', id: nilUUID }, true); + }} + disabled={connection.updating || hasError} + /> + )} + <Button + variant="outline" + className="flex-grow" + label="Cancel" + disabled={props.disableCancel} + onClick={(event) => { + event.preventDefault(); + closeDialog(); + }} + /> + </div> + </> + </DialogContent> </Dialog> ); }; diff --git a/libs/shared/lib/querybuilder/model/graphology/model.ts b/libs/shared/lib/querybuilder/model/graphology/model.ts index 4e4cc935d2111b1927334c638011373dbbfc8395..b47deeb6e08999538cef80e4c2d163a78125eda8 100644 --- a/libs/shared/lib/querybuilder/model/graphology/model.ts +++ b/libs/shared/lib/querybuilder/model/graphology/model.ts @@ -33,6 +33,7 @@ export interface EntityData { leftRelationHandleId?: QueryGraphEdgeHandle; rightRelationHandleId?: QueryGraphEdgeHandle; selected?: boolean; + type: QueryElementTypes.Entity; } /** Interface for the data in an relation node. */ @@ -44,6 +45,7 @@ export interface RelationData { rightEntityHandleId?: QueryGraphEdgeHandle; direction?: 'left' | 'right' | 'both'; selected?: boolean; + type: QueryElementTypes.Relation; } export interface LogicData { @@ -53,11 +55,12 @@ export interface LogicData { // key: string; logic: GeneralDescription<AllLogicTypes>; inputs: Record<string, InputNodeTypeTypes>; // name from InputNode -> InputNodeTypeTypes + type: QueryElementTypes.Logic; } -export type EntityNodeAttributes = XYPosition & EntityData & NodeDefaults; -export type RelationNodeAttributes = XYPosition & RelationData & NodeDefaults; -export type LogicNodeAttributes = XYPosition & LogicData & NodeDefaults; +export type EntityNodeAttributes = XYPosition & NodeDefaults & EntityData; +export type RelationNodeAttributes = XYPosition & NodeDefaults & RelationData; +export type LogicNodeAttributes = XYPosition & NodeDefaults & LogicData; export type QueryGraphNodes = EntityNodeAttributes | RelationNodeAttributes | LogicNodeAttributes; diff --git a/libs/shared/lib/querybuilder/model/graphology/utils.ts b/libs/shared/lib/querybuilder/model/graphology/utils.ts index c2d3ae3996cbbd0d28469e7900a9d85b4d7956ff..f08865788e95edfd3ffd42c6ae8a4002f2e4dae2 100644 --- a/libs/shared/lib/querybuilder/model/graphology/utils.ts +++ b/libs/shared/lib/querybuilder/model/graphology/utils.ts @@ -54,8 +54,6 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges if (!attributes.id) attributes.id = 'id_' + (Date.now() + Math.floor(Math.random() * 1000)).toString(); - attributes.attributes = attributes.attributes || []; - // Add to the beginning the meta attributes, such as (# Connection) attributes.attributes = [...checkForMetaAttributes(attributes).map((a) => ({ handleData: a })), ...attributes.attributes]; @@ -118,19 +116,17 @@ export class QueryMultiGraphology extends Graph<QueryGraphNodes, QueryGraphEdges return attributes; } - public addLogicPill2Graphology(attributes: QueryGraphNodes, inputValues: Record<string, InputNodeTypeTypes> = {}): QueryGraphNodes { - attributes = this.configureDefaults(attributes); - if (!attributes.type) attributes.type = QueryElementTypes.Logic; + public addLogicPill2Graphology(attributes: LogicNodeAttributes, inputValues: Record<string, InputNodeTypeTypes> = {}): QueryGraphNodes { + attributes = this.configureDefaults(attributes) as LogicNodeAttributes; if (!attributes.name || !attributes.id) throw Error('type or name is not defined'); // add default inputs, but only if not there yet if (attributes.type === QueryElementTypes.Logic) { - if ((attributes as LogicNodeAttributes).inputs === undefined) { - attributes = attributes as LogicNodeAttributes; - (attributes as LogicNodeAttributes).logic.inputs.forEach((input, i) => { + if (attributes.inputs === undefined || Object.keys(attributes.inputs).length === 0) { + attributes.logic.inputs.forEach((input, i) => { // Setup default non-linked inputs as regular values matching the input expected type - if (!(attributes as LogicNodeAttributes).inputs) (attributes as LogicNodeAttributes).inputs = {}; - (attributes as LogicNodeAttributes).inputs[input.name] = inputValues?.[input.name] || input.default; + if (!attributes.inputs) attributes.inputs = {}; + attributes.inputs[input.name] = inputValues?.[input.name] || input.default; }); // (attributes as LogicNodeAttributes).leftEntityHandleId = getHandleId(attributes.id, name, type, Handles.RelationLeft, ''); // (attributes as LogicNodeAttributes).rightEntityHandleId = getHandleId(attributes.id, name, type, Handles.RelationRight, ''); diff --git a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx index 26da1edfb41b03e3e960c6d7ee7e1acf8b5028fc..a54e5e213aba9371059578c3a8d60269755d8d8f 100644 --- a/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx +++ b/libs/shared/lib/querybuilder/panel/QueryBuilder.tsx @@ -195,6 +195,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { y: position.y - mouse_y, name: dragData.name, schemaKey: dragData.name, + attributes: [], }, schema.getNodeAttribute(dragData.name, 'attributes'), ); @@ -212,6 +213,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { name: dragData.collection, schemaKey: dragData.label, collection: dragData.collection, + attributes: [], }, schema.getEdgeAttribute(dragData.label, 'attributes'), ); @@ -238,6 +240,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { y: position.y, name: fromNodeID, schemaKey: fromNodeID, + attributes: [], }, schema.getNodeAttribute(fromNodeID, 'attributes'), ); @@ -249,6 +252,7 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { y: position.y, name: toNodeID, schemaKey: toNodeID, + attributes: [], }, schema.getNodeAttribute(toNodeID, 'attributes'), ); @@ -280,6 +284,8 @@ export const QueryBuilderInner = (props: QueryBuilderProps) => { x: position.x, y: position.y, logic: logic, + attributes: [], + inputs: {}, }); dispatch(setQuerybuilderGraphology(graphologyGraph)); diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx index 041acb8dfad4987c3d2863f57333983d0243ecde..0b9f7cff881741335e9413acaf28882b0b38eba6 100644 --- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx +++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderLogicPillsPanel.tsx @@ -86,6 +86,8 @@ export const QueryBuilderLogicPillsPanel = (props: { x: bounds.width / 2, y: bounds.height / 2, logic: logic, + attributes: [], + inputs: {}, }); } else { const params = props.connection.params; @@ -97,6 +99,8 @@ export const QueryBuilderLogicPillsPanel = (props: { x: position.x, y: position.y, logic: logic, + attributes: [], + inputs: {}, }); if (!logicNode?.id) throw new Error('Logic node has no id'); diff --git a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx index 3b57002c3b1a5fc19656a596182ecd959f5e6425..5b398a8d50a65ec8cc45697e1bd2dd78950dbdac 100644 --- a/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx +++ b/libs/shared/lib/querybuilder/panel/querysidepanel/queryBuilderRelatedNodesPanel.tsx @@ -91,6 +91,7 @@ export const QueryBuilderRelatedNodesPanel = (props: { y: position.y, name: entity.name, schemaKey: entity.name, + attributes: [], }, schemaGraph.getNodeAttribute(entity.name, 'attributes'), ); @@ -124,6 +125,7 @@ export const QueryBuilderRelatedNodesPanel = (props: { depth: { min: queryBuilderSettings.depth.min, max: queryBuilderSettings.depth.max }, name: relation.collection, collection: relation.collection, + attributes: [], }, schemaGraph.getEdgeAttribute(relation.label, 'attributes'), ); diff --git a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx index d26c952c0145b00706c06aba3a8d85d7dab22d4b..0868585845f4df0ac04de36f8d7fe5887fab34c5 100644 --- a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx +++ b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdown.tsx @@ -1,5 +1,12 @@ import { useMemo, ReactElement, useState, useContext } from 'react'; -import { Handles, NodeAttribute, QueryElementTypes, QueryGraphEdges, SchemaReactflowEntityNode } from '../../model'; +import { + Handles, + NodeAttribute, + QueryElementTypes, + QueryGraphEdges, + SchemaReactflowEntityNode, + SchemaReactflowRelationNode, +} from '../../model'; import { Abc, CalendarToday, Map, Numbers, Place, QuestionMarkOutlined } from '@mui/icons-material'; import { Button, TextInput, useAppDispatch, useQuerybuilderAttributesShown } from '../../..'; import { attributeShownToggle } from '@graphpolaris/shared/lib/data-access/store/querybuilderSlice'; @@ -8,7 +15,7 @@ import { QueryBuilderDispatcherContext } from '../../panel/QueryBuilderDispatche import { PillDropdownItem } from './PillDropdownItem'; type PillDropdownProps = { - node: SchemaReactflowEntityNode; + node: SchemaReactflowEntityNode | SchemaReactflowRelationNode; attributes: NodeAttribute[]; attributeEdges: (QueryGraphEdges | undefined)[]; open: boolean; diff --git a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx index 161a42ab6d3f955ad82da5a82cbf8c20cfb503b1..6304229d14cbdff0438f6d2b60c623002456171a 100644 --- a/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx +++ b/libs/shared/lib/querybuilder/pills/pilldropdown/PillDropdownItem.tsx @@ -1,5 +1,11 @@ import { ReactElement, useContext } from 'react'; -import { NodeAttribute, SchemaReactflowEntityNode, handleDataFromReactflowToDataId, toHandleId } from '../../model'; +import { + NodeAttribute, + SchemaReactflowEntityNode, + SchemaReactflowRelationNode, + handleDataFromReactflowToDataId, + toHandleId, +} from '../../model'; import { Handle, Position } from 'reactflow'; import { PillHandle } from '@graphpolaris/shared/lib/components/pills/PillHandle'; import { pillDropdownPadding } from '@graphpolaris/shared/lib/components/pills/pill.const'; @@ -8,7 +14,7 @@ import { QueryBuilderDispatcherContext } from '../../panel/QueryBuilderDispatche type PillDropdownItemProps = { attribute: NodeAttribute; - node: SchemaReactflowEntityNode; + node: SchemaReactflowEntityNode | SchemaReactflowRelationNode; className?: string; mr?: number; icon: ReactElement; diff --git a/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts b/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts index a2ed912b992d56b664adc30a5bf22b9dda77477a..8b35dba9498b26054d57f7706d4792ca838a1693 100644 --- a/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts +++ b/libs/shared/lib/querybuilder/query-utils/query2backend.spec.ts @@ -14,6 +14,7 @@ const defaultQuery = { query: [], limit: 500, return: ['*'], + machineLearning: [], }; const defaultSettings: QueryBuilderSettings = { @@ -38,6 +39,7 @@ describe('QueryUtils Entity and Relations', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }); const entity2 = graph.addPill2Graphology({ id: '10', @@ -45,6 +47,7 @@ describe('QueryUtils Entity and Relations', () => { x: 200, y: 200, name: 'Airport 2', + attributes: [], }); const relation1 = graph.addPill2Graphology({ @@ -55,6 +58,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(entity1, relation1); @@ -90,8 +94,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run multiple path query translation', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' }); + const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -101,13 +105,14 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1, { type: 'connection' }); graph.addEdge2Graphology(r1, e2, { type: 'connection' }); - const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' }); - const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' }); + const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] }); + const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] }); const r12 = graph.addPill2Graphology({ id: 'r12', @@ -117,6 +122,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports 2', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e12, r12); @@ -169,10 +175,10 @@ describe('QueryUtils Entity and Relations', () => { it('should run one relation multiple entity query translation', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' }); - const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' }); - const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] }); + const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] }); + const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -182,6 +188,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1); @@ -235,10 +242,10 @@ describe('QueryUtils Entity and Relations', () => { it('should run lone entities query translation', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' }); - const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12' }); - const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22' }); + const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] }); + const e12 = graph.addPill2Graphology({ id: 'e12', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 12', attributes: [] }); + const e22 = graph.addPill2Graphology({ id: 'e22', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 22', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -248,6 +255,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1); @@ -276,8 +284,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run lone relations query translation', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2' }); + const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 200, y: 200, name: 'Airport 2', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -287,6 +295,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); const r2 = graph.addPill2Graphology({ id: 'r2', @@ -296,6 +305,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports 2', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1); @@ -326,7 +336,7 @@ describe('QueryUtils Entity and Relations', () => { it('should run relation only left side connected query translation', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -336,6 +346,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1); @@ -361,7 +372,7 @@ describe('QueryUtils Entity and Relations', () => { it('should run relation only right side connected query translation', () => { const graph = new QueryMultiGraphology(); - const e2 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2' }); + const e2 = graph.addPill2Graphology({ id: 'e0', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -371,6 +382,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(r1, e2); @@ -394,8 +406,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run entity and relations multi connection', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 2', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -405,6 +417,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); const r2 = graph.addPill2Graphology({ @@ -415,6 +428,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports 2', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1); @@ -451,7 +465,7 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of loops', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -461,6 +475,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1, { type: 'connection' }); @@ -487,8 +502,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of loops and regular', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -498,6 +513,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1, { type: 'connection' }); @@ -538,8 +554,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of loops and regular left', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); const r1 = graph.addPill2Graphology({ id: 'r1', @@ -549,6 +565,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(e1, r1, { type: 'connection' }); @@ -584,8 +601,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of direct entity connection', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); graph.addEdge2Graphology(e1, e2, { type: 'connection' }); @@ -618,6 +635,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); const r2 = graph.addPill2Graphology({ @@ -628,6 +646,7 @@ describe('QueryUtils Entity and Relations', () => { name: 'Flight between airports 2', collection: 'Relation Pill', depth: { min: 0, max: 1 }, + attributes: [], }); graph.addEdge2Graphology(r1, r2, { type: 'connection' }); @@ -656,8 +675,8 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of entity only loop', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); - const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); + const e2 = graph.addPill2Graphology({ id: 'e2', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); graph.addEdge2Graphology(e1, e2, { type: 'connection' }); graph.addEdge2Graphology(e2, e1, { type: 'connection' }); @@ -691,7 +710,7 @@ describe('QueryUtils Entity and Relations', () => { it('should run in case of entity only self loop', () => { const graph = new QueryMultiGraphology(); - const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1' }); + const e1 = graph.addPill2Graphology({ id: 'e1', type: QueryElementTypes.Entity, x: 100, y: 100, name: 'Airport 1', attributes: [] }); graph.addEdge2Graphology(e1, e1, { type: 'connection' }); @@ -721,6 +740,7 @@ describe('QueryUtils calculateQueryLogic', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -732,6 +752,8 @@ describe('QueryUtils calculateQueryLogic', () => { y: 100, name: 'Logic 1', logic: MathFilters[NumberFilterTypes.EQUAL], + attributes: [], + inputs: {}, }); graph.addEdge2Graphology(e1, l1, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: '1' }); @@ -754,6 +776,7 @@ describe('QueryUtils with Logic', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -765,6 +788,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Logic 1', logic: MathFilters[NumberFilterTypes.EQUAL], + attributes: [], + inputs: {}, }); graph.addEdge2Graphology(e1, l1, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' }); @@ -800,6 +825,7 @@ describe('QueryUtils with Logic', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -811,6 +837,7 @@ describe('QueryUtils with Logic', () => { x: 100, y: 100, name: 'Airport 2', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -822,6 +849,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Filter EQ', logic: MathFilters[NumberFilterTypes.EQUAL], + attributes: [], + inputs: {}, }); const l2 = graph.addLogicPill2Graphology({ @@ -831,6 +860,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Logic ADD', logic: NumberFunctions[NumberFunctionTypes.ADD], + attributes: [], + inputs: {}, }); graph.addEdge2Graphology(e1, l2, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' }); @@ -876,6 +907,7 @@ describe('QueryUtils with Logic', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -887,6 +919,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Logic LT', logic: MathFilters[NumberFilterTypes.LESS_THAN], + attributes: [], + inputs: {}, }); const l2 = graph.addLogicPill2Graphology({ @@ -896,6 +930,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Logic average', logic: MathAggregations[NumberAggregationTypes.AVG], + attributes: [], + inputs: {}, }); graph.addEdge2Graphology(e1, l2, { type: 'connection' }, { sourceHandleName: 'age', targetHandleName: 'Value' }); @@ -932,6 +968,7 @@ describe('QueryUtils with Logic', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -944,6 +981,8 @@ describe('QueryUtils with Logic', () => { y: 100, name: 'Logic LT', logic: MathFilters[NumberFilterTypes.LESS_THAN], + attributes: [], + inputs: {}, }, { '1': 5 }, ); @@ -982,6 +1021,7 @@ it('should no connections between entities and relations', () => { x: 100, y: 100, name: 'Airport 1', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -993,6 +1033,7 @@ it('should no connections between entities and relations', () => { x: 100, y: 100, name: 'Airport 2', + attributes: [], }, [{ name: 'age', type: 'string' }], ); @@ -1004,6 +1045,8 @@ it('should no connections between entities and relations', () => { y: 100, name: 'Relation 1', depth: { min: 0, max: 1 }, + attributes: [], + collection: 'r', }, [{ name: 'age', type: 'string' }], ); diff --git a/libs/shared/lib/querybuilder/query-utils/query2backend.ts b/libs/shared/lib/querybuilder/query-utils/query2backend.ts index fc1aa99427b78d660ee900b6024a3d0016ffbe0c..f04b9f1cf72eddc9e47b1308d97d007400dcf044 100644 --- a/libs/shared/lib/querybuilder/query-utils/query2backend.ts +++ b/libs/shared/lib/querybuilder/query-utils/query2backend.ts @@ -31,7 +31,7 @@ const traverseEntityRelationPaths = ( // console.log('new path'); paths.push([]); if (node.attributes.type === QueryElementTypes.Relation) { - paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.y }); + paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.y, attributes: [] }); } } else if (paths[currentIdx].length > 0) { const lastNode = paths[currentIdx][paths[currentIdx].length - 1]; @@ -39,13 +39,15 @@ const traverseEntityRelationPaths = ( if (lastNode.type === QueryElementTypes.Entity) { paths[currentIdx].push({ type: QueryElementTypes.Relation, + collection: node.key, x: node.attributes.x, y: node.attributes.x, depth: { min: settings.depth.min, max: settings.depth.max }, direction: 'both', + attributes: [], }); } else { - paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x }); + paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x, attributes: [] }); } } } @@ -59,7 +61,7 @@ const traverseEntityRelationPaths = ( let connections = edges.filter((e) => e.source === node.key); if (connections.length === 0) { if (node.attributes.type === QueryElementTypes.Relation) { - paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x }); + paths[currentIdx].push({ type: QueryElementTypes.Entity, x: node.attributes.x, y: node.attributes.x, attributes: [] }); } return 0; }