From 61c6988ca6db24e37c2eb477efa00ba83eb7cfce Mon Sep 17 00:00:00 2001 From: Andreja Tonev Date: Wed, 28 Feb 2024 17:48:50 +0100 Subject: [PATCH 1/5] Adds properties on edges one_to_many: passing field parameters (which already existed but was not used) many_to_many: changed from parameters to column_names_mapping using the mapping and columns to define properties ignoring from to keys when adding properties --- .../transformations/importing/loaders.py | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/gqlalchemy/transformations/importing/loaders.py b/gqlalchemy/transformations/importing/loaders.py index 67292622..025cb7b7 100644 --- a/gqlalchemy/transformations/importing/loaders.py +++ b/gqlalchemy/transformations/importing/loaders.py @@ -41,6 +41,7 @@ ) from gqlalchemy.query_builders.memgraph_query_builder import Operator, QueryBuilder, Unwind from gqlalchemy.transformations.importing.importer import Importer +from gqlalchemy.utilities import to_cypher_properties NAME_MAPPINGS_KEY = "name_mappings" ONE_TO_MANY_RELATIONS_KEY = "one_to_many_relations" @@ -103,7 +104,7 @@ class OneToManyMapping: foreign_key: ForeignKeyMapping label: str from_entity: bool = False - parameters: Optional[Dict[str, str]] = None + parameters: Optional[Dict[str, Any]] = None @dataclass(frozen=True) @@ -115,13 +116,13 @@ class ManyToManyMapping: foreign_key_from: Describes the source of the relationship. foreign_key_to: Describes the destination of the relationship. label: Label to be applied to the newly created relationship. - parameters: Parameters that will be added to the relationship created from this object (Optional). + column_names_mapping: Dictionary containing key-value pairs in form ("column name", "property name") (Optional). """ foreign_key_from: ForeignKeyMapping foreign_key_to: ForeignKeyMapping label: str - parameters: Optional[Dict[str, str]] = None + column_names_mapping: Dict[str, str] = field(default_factory=dict) Mapping = Union[List[OneToManyMapping], ManyToManyMapping] @@ -412,7 +413,13 @@ class TableToGraphImporter(Importer): @staticmethod def _create_trigger_cypher_query( - label1: str, label2: str, property1: str, property2: str, relationship_type: str, from_entity: bool + label1: str, + label2: str, + property1: str, + property2: str, + relationship_type: str, + relationship_parameters: Dict[str, Any], + from_entity: bool, ) -> str: """Creates a Cypher query for the translation trigger. @@ -426,6 +433,11 @@ def _create_trigger_cypher_query( """ from_node, to_node = TableToGraphImporter._DIRECTION[from_entity] + # Add properties to the edge definition + # Using -[:$label]- to get -[:LABEL{property key-value pairs}] + if relationship_parameters is not None: + relationship_type += to_cypher_properties(relationship_parameters) + return TableToGraphImporter._TriggerQueryTemplate.substitute( node_a=NODE_A, node_b=NODE_B, @@ -494,6 +506,7 @@ def _load_cross_relationships(self) -> None: property_from=mapping_from.reference_key, property_to=mapping_to.reference_key, relation_label=many_to_many_mapping.mapping.label, + relation_mappings=many_to_many_mapping.mapping.column_names_mapping, row=row, ) @@ -518,6 +531,7 @@ def _create_triggers(self) -> None: ) relationship_type = mapping.label from_entity = mapping.from_entity + relationship_parameters = mapping.parameters self._create_trigger( label1=label1, @@ -525,6 +539,7 @@ def _create_triggers(self) -> None: property1=property1, property2=property2, relationship_type=relationship_type, + relationship_parameters=relationship_parameters, from_entity=from_entity, ) self._create_trigger( @@ -533,11 +548,19 @@ def _create_triggers(self) -> None: property1=property2, property2=property1, relationship_type=relationship_type, + relationship_parameters=relationship_parameters, from_entity=not from_entity, ) def _create_trigger( - self, label1: str, label2: str, property1: str, property2: str, relationship_type: str, from_entity: bool + self, + label1: str, + label2: str, + property1: str, + property2: str, + relationship_type: str, + relationship_parameters: Dict[str, Any], + from_entity: bool, ) -> None: """Creates a translation trigger in Memgraph. @@ -557,7 +580,7 @@ def _create_trigger( event_object=TriggerEventObject.NODE, execution_phase=TriggerExecutionPhase.BEFORE, statement=TableToGraphImporter._create_trigger_cypher_query( - label1, label2, property1, property2, relationship_type, from_entity + label1, label2, property1, property2, relationship_type, relationship_parameters, from_entity ), ) @@ -606,6 +629,7 @@ def _save_row_as_relationship( property_from: str, property_to: str, relation_label: str, + relation_mappings: Dict[str, str], row: Dict[str, Any], ) -> None: """Translates a row to a relationship and writes it to Memgraph. @@ -642,7 +666,10 @@ def _save_row_as_relationship( ) .create() .node(variable=NODE_A) - .to(relation_label) + .to( + relationship_type=relation_label, + **{relation_mappings.get(k, k): v for k, v in row.items() if k != property_to and k != property_from}, + ) .node(variable=NODE_B) .execute() ) From f9b1a18a0f1970bf60338cc8ced489dfcba29961 Mon Sep 17 00:00:00 2001 From: Andreja Tonev Date: Thu, 29 Feb 2024 11:44:08 +0100 Subject: [PATCH 2/5] Added tests --- .../transformations/loaders/data/address.csv | 5 +++ tests/transformations/loaders/data/i2a.csv | 3 ++ .../loaders/data/individual.csv | 6 +++ tests/transformations/loaders/test_loaders.py | 37 +++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/transformations/loaders/data/address.csv create mode 100644 tests/transformations/loaders/data/i2a.csv create mode 100644 tests/transformations/loaders/data/individual.csv diff --git a/tests/transformations/loaders/data/address.csv b/tests/transformations/loaders/data/address.csv new file mode 100644 index 00000000..54c2575e --- /dev/null +++ b/tests/transformations/loaders/data/address.csv @@ -0,0 +1,5 @@ +add_id,street,street_num,city +1,Ilica,2,Zagreb +2,Death Valley,0,Knowhere +3,Horvacanska,3,Horvati +4,Broadway,12,New York diff --git a/tests/transformations/loaders/data/i2a.csv b/tests/transformations/loaders/data/i2a.csv new file mode 100644 index 00000000..3397e97f --- /dev/null +++ b/tests/transformations/loaders/data/i2a.csv @@ -0,0 +1,3 @@ +add_id,ind_id,duration +1,2,12 +2,1,5 diff --git a/tests/transformations/loaders/data/individual.csv b/tests/transformations/loaders/data/individual.csv new file mode 100644 index 00000000..c007d8d5 --- /dev/null +++ b/tests/transformations/loaders/data/individual.csv @@ -0,0 +1,6 @@ +ind_id,name,surname,add_id +1,Tomislav,Petrov,1 +2,Ivan,Horvat,3 +3,Marko,Horvat,3 +4,John,Doe,2 +5,John,Though,4 diff --git a/tests/transformations/loaders/test_loaders.py b/tests/transformations/loaders/test_loaders.py index 6d8e64cc..6d4773f1 100644 --- a/tests/transformations/loaders/test_loaders.py +++ b/tests/transformations/loaders/test_loaders.py @@ -106,6 +106,43 @@ def test_local_table_to_graph_importer_csv(memgraph): importer = CSVLocalFileSystemImporter(path=path, data_configuration=my_configuration, memgraph=memgraph) importer.translate(drop_database_on_start=True) + conf_with_edge_params = { + "indices": {"address": ["add_id"], "individual": ["ind_id"]}, + "name_mappings": {"individual": {"label": "INDIVIDUAL"}, "address": {"label": "ADDRESS"}}, + "one_to_many_relations": { + "address": [], + "individual": [ + { + "foreign_key": {"column_name": "add_id", "reference_table": "address", "reference_key": "add_id"}, + "label": "LIVES_IN", + "parameters": {"p": "this is fixed for all edges"}, + } + ], + }, + } + importer = CSVLocalFileSystemImporter(path=path, data_configuration=conf_with_edge_params, memgraph=memgraph) + importer.translate(drop_database_on_start=True) + + conf_with_many_to_many = { + "indices": {"address": ["add_id"], "individual": ["ind_id"]}, + "name_mappings": {"individual": {"label": "INDIVIDUAL"}, "address": {"label": "ADDRESS"}}, + "one_to_many_relations": {"address": [], "individual": []}, + "many_to_many_relations": { + "i2a": { + "foreign_key_from": { + "column_name": "ind_id", + "reference_table": "individual", + "reference_key": "ind_id", + }, + "foreign_key_to": {"column_name": "add_id", "reference_table": "address", "reference_key": "add_id"}, + "label": "LIVES_IN", + "column_names_mapping": {"duration": "years"}, + } + }, + } + importer = CSVLocalFileSystemImporter(path=path, data_configuration=conf_with_many_to_many, memgraph=memgraph) + importer.translate(drop_database_on_start=True) + @pytest.mark.extras @pytest.mark.arrow From 397f25cece95c64c17e23768d5d80b26b1c44a63 Mon Sep 17 00:00:00 2001 From: Andreja Tonev Date: Tue, 25 Jun 2024 11:51:00 +0200 Subject: [PATCH 3/5] Removed one_to_many parameters + Using NameMapper for many_to_many properties --- .../transformations/importing/loaders.py | 47 ++++++------------- tests/transformations/loaders/test_loaders.py | 11 +++-- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/gqlalchemy/transformations/importing/loaders.py b/gqlalchemy/transformations/importing/loaders.py index 025cb7b7..c66e9b47 100644 --- a/gqlalchemy/transformations/importing/loaders.py +++ b/gqlalchemy/transformations/importing/loaders.py @@ -41,7 +41,6 @@ ) from gqlalchemy.query_builders.memgraph_query_builder import Operator, QueryBuilder, Unwind from gqlalchemy.transformations.importing.importer import Importer -from gqlalchemy.utilities import to_cypher_properties NAME_MAPPINGS_KEY = "name_mappings" ONE_TO_MANY_RELATIONS_KEY = "one_to_many_relations" @@ -98,13 +97,11 @@ class OneToManyMapping: foreign_key: Foreign key used for mapping. label: Label which will be applied to the relationship created from this object. from_entity: Direction of the relationship created from the mapping object. - parameters: Parameters that will be added to the relationship created from this object (Optional). """ foreign_key: ForeignKeyMapping label: str from_entity: bool = False - parameters: Optional[Dict[str, Any]] = None @dataclass(frozen=True) @@ -116,13 +113,13 @@ class ManyToManyMapping: foreign_key_from: Describes the source of the relationship. foreign_key_to: Describes the destination of the relationship. label: Label to be applied to the newly created relationship. - column_names_mapping: Dictionary containing key-value pairs in form ("column name", "property name") (Optional). + parameters: Properties that will be added to the relationship created from this object (Optional). """ foreign_key_from: ForeignKeyMapping foreign_key_to: ForeignKeyMapping label: str - column_names_mapping: Dict[str, str] = field(default_factory=dict) + parameters: Optional[List[str]] = None Mapping = Union[List[OneToManyMapping], ManyToManyMapping] @@ -413,13 +410,7 @@ class TableToGraphImporter(Importer): @staticmethod def _create_trigger_cypher_query( - label1: str, - label2: str, - property1: str, - property2: str, - relationship_type: str, - relationship_parameters: Dict[str, Any], - from_entity: bool, + label1: str, label2: str, property1: str, property2: str, relationship_type: str, from_entity: bool ) -> str: """Creates a Cypher query for the translation trigger. @@ -433,11 +424,6 @@ def _create_trigger_cypher_query( """ from_node, to_node = TableToGraphImporter._DIRECTION[from_entity] - # Add properties to the edge definition - # Using -[:$label]- to get -[:LABEL{property key-value pairs}] - if relationship_parameters is not None: - relationship_type += to_cypher_properties(relationship_parameters) - return TableToGraphImporter._TriggerQueryTemplate.substitute( node_a=NODE_A, node_b=NODE_B, @@ -506,7 +492,8 @@ def _load_cross_relationships(self) -> None: property_from=mapping_from.reference_key, property_to=mapping_to.reference_key, relation_label=many_to_many_mapping.mapping.label, - relation_mappings=many_to_many_mapping.mapping.column_names_mapping, + table_name=many_to_many_mapping.table_name, + parameters=many_to_many_mapping.mapping.parameters, row=row, ) @@ -531,7 +518,6 @@ def _create_triggers(self) -> None: ) relationship_type = mapping.label from_entity = mapping.from_entity - relationship_parameters = mapping.parameters self._create_trigger( label1=label1, @@ -539,7 +525,6 @@ def _create_triggers(self) -> None: property1=property1, property2=property2, relationship_type=relationship_type, - relationship_parameters=relationship_parameters, from_entity=from_entity, ) self._create_trigger( @@ -548,19 +533,11 @@ def _create_triggers(self) -> None: property1=property2, property2=property1, relationship_type=relationship_type, - relationship_parameters=relationship_parameters, from_entity=not from_entity, ) def _create_trigger( - self, - label1: str, - label2: str, - property1: str, - property2: str, - relationship_type: str, - relationship_parameters: Dict[str, Any], - from_entity: bool, + self, label1: str, label2: str, property1: str, property2: str, relationship_type: str, from_entity: bool ) -> None: """Creates a translation trigger in Memgraph. @@ -580,7 +557,7 @@ def _create_trigger( event_object=TriggerEventObject.NODE, execution_phase=TriggerExecutionPhase.BEFORE, statement=TableToGraphImporter._create_trigger_cypher_query( - label1, label2, property1, property2, relationship_type, relationship_parameters, from_entity + label1, label2, property1, property2, relationship_type, from_entity ), ) @@ -629,7 +606,8 @@ def _save_row_as_relationship( property_from: str, property_to: str, relation_label: str, - relation_mappings: Dict[str, str], + table_name: str, + parameters: List[str], row: Dict[str, Any], ) -> None: """Translates a row to a relationship and writes it to Memgraph. @@ -640,6 +618,8 @@ def _save_row_as_relationship( property_from: Property of the source node. property_to: Property of the destination node. relation_label: Label for the relationship. + table_name: Name of the table used to read parameters + parameters: Relationship parameters to be added row: The row to be translated. """ ( @@ -668,7 +648,10 @@ def _save_row_as_relationship( .node(variable=NODE_A) .to( relationship_type=relation_label, - **{relation_mappings.get(k, k): v for k, v in row.items() if k != property_to and k != property_from}, + **{ + self._name_mapper.get_property_name(collection_name=table_name, column_name=prop): row[prop] + for prop in parameters + }, ) .node(variable=NODE_B) .execute() diff --git a/tests/transformations/loaders/test_loaders.py b/tests/transformations/loaders/test_loaders.py index 6d4773f1..818bbfa7 100644 --- a/tests/transformations/loaders/test_loaders.py +++ b/tests/transformations/loaders/test_loaders.py @@ -115,7 +115,6 @@ def test_local_table_to_graph_importer_csv(memgraph): { "foreign_key": {"column_name": "add_id", "reference_table": "address", "reference_key": "add_id"}, "label": "LIVES_IN", - "parameters": {"p": "this is fixed for all edges"}, } ], }, @@ -125,7 +124,13 @@ def test_local_table_to_graph_importer_csv(memgraph): conf_with_many_to_many = { "indices": {"address": ["add_id"], "individual": ["ind_id"]}, - "name_mappings": {"individual": {"label": "INDIVIDUAL"}, "address": {"label": "ADDRESS"}}, + "name_mappings": { + "individual": {"label": "INDIVIDUAL"}, + "address": {"label": "ADDRESS"}, + "i2a": { + "column_names_mapping": {"duration": "years"}, + } + }, "one_to_many_relations": {"address": [], "individual": []}, "many_to_many_relations": { "i2a": { @@ -136,7 +141,7 @@ def test_local_table_to_graph_importer_csv(memgraph): }, "foreign_key_to": {"column_name": "add_id", "reference_table": "address", "reference_key": "add_id"}, "label": "LIVES_IN", - "column_names_mapping": {"duration": "years"}, + "parameters": ["duration"] } }, } From 1f59c4da6418535564ca9820b386e48dce4d34d2 Mon Sep 17 00:00:00 2001 From: Andreja Tonev Date: Tue, 25 Jun 2024 18:30:49 +0200 Subject: [PATCH 4/5] Docs --- .../import-table-data-to-graph-database.md | 99 ++++++++++++++++--- .../transformations/importing/loaders.md | 3 +- 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/docs/how-to-guides/loaders/import-table-data-to-graph-database.md b/docs/how-to-guides/loaders/import-table-data-to-graph-database.md index 964f2760..08818f3a 100644 --- a/docs/how-to-guides/loaders/import-table-data-to-graph-database.md +++ b/docs/how-to-guides/loaders/import-table-data-to-graph-database.md @@ -27,14 +27,21 @@ data is located, here are two guides on how to import it to Memgraph: ## Loading a CSV file from the local file system -Let's say you have a simple table data in a CSV file stored at -`/home/user/table_data`: +Let's say you have a simple dataset stored in CSV files: +`/home/user/table_data/individual.csv`: ```csv -name,surname,grade -Ivan,Horvat,4 -Marko,Andric,5 -Luka,Lukic,3 +ind_id, name, surname, add_id +1, Ivan, Horvat, 2 +2, Marko, Andric, 2 +3, Luka, Lukic, 1 +``` + +`/home/user/table_data/address.csv`: +```csv +add_id, street, num, city +1, Ilica, 2, Zagreb +2, Broadway, 12, New York ``` To create a translation from table to graph data, you need to define a **data @@ -78,24 +85,37 @@ many_to_many_relations: # intended to be used in case of associative table column_name: reference_table: reference_key: - label: + label: # relationship's label + parameters: # list of parameters to add to the relationship ``` +### One to many + For this example, you don't need all of those fields. You only need to define `indices` and `one_to_many_relations`. Hence, you have the following YAML file: ```yaml indices: - example: - - name + address: + - add_id + individual: + - ind_id name_mappings: - example: - label: PERSON + individual: + label: INDIVIDUAL + address: + label: ADDRESS one_to_many_relations: - example: [] + address: [] + individual: + - foreign_key: + column_name: add_id + reference_table: address + reference_key: add_id + label: LIVES_IN ``` In order to read the data configuration from the YAML file, run: @@ -114,12 +134,65 @@ make an instance of an `Importer` and call `translate()`. ```python importer = CSVLocalFileSystemImporter( data_configuration=parsed_yaml, - path="/home/user/table_data", + path="/home/user/table_data/", ) importer.translate(drop_database_on_start=True) ``` +### Many to many + +Relationships can also be defined using a third, associative table. + +`/home/user/table_data/tenant.csv`: +```csv +ind_id, add_id, duration +1, 2, 21 +2, 2, 3 +3, 1, 5 +``` + +We need to extend our data configuration YAML file to include the `many_to_many_relations`, like so: + +``` +indices: + address: + - add_id + individual: + - ind_id + +name_mappings: + individual: + label: INDIVIDUAL + address: + label: ADDRESS + tenant: + column_names_mapping: + duration: years + +one_to_many_relations: + address: [] + individual: [] + +many_to_many_relations: + tenant: + foreign_key_from: + column_name: ind_id + reference_table: individual + reference_key: ind_id + foreign_key_to: + column_name: add_id + reference_table: address + reference_key: add_id + label: LIVES_IN + parameters: + - duration +``` + +From here the procedure is the same as before. +In addition to having imported nodes and connected individuals and their addresses, we have also added an edge property. +This property is read from the associative table and is named in accordance with the `name_mappings`. + ## Using a cloud storage solution To connect to Azure Blob, simply change the Importer object you are using. Like diff --git a/docs/reference/gqlalchemy/transformations/importing/loaders.md b/docs/reference/gqlalchemy/transformations/importing/loaders.md index 5d8c9fe9..1939098d 100644 --- a/docs/reference/gqlalchemy/transformations/importing/loaders.md +++ b/docs/reference/gqlalchemy/transformations/importing/loaders.md @@ -27,7 +27,6 @@ Class that holds the full description of a single one to many mapping in a table - `foreign_key` - Foreign key used for mapping. - `label` - Label which will be applied to the relationship created from this object. - `from_entity` - Direction of the relationship created from the mapping object. -- `parameters` - Parameters that will be added to the relationship created from this object (Optional). ## ManyToManyMapping Objects @@ -44,7 +43,7 @@ Many to many mapping is intended to be used in case of associative tables. - `foreign_key_from` - Describes the source of the relationship. - `foreign_key_to` - Describes the destination of the relationship. - `label` - Label to be applied to the newly created relationship. -- `parameters` - Parameters that will be added to the relationship created from this object (Optional). +- `parameters` - List of parameters that will be added to the relationship created from this object (Optional). ## TableMapping Objects From 1d246585361a94b31ff92becc212b64d5047de0e Mon Sep 17 00:00:00 2001 From: Andreja Tonev Date: Tue, 2 Jul 2024 10:14:47 +0200 Subject: [PATCH 5/5] choosing the properties keyword over parameters --- .../loaders/import-table-data-to-graph-database.md | 4 ++-- .../transformations/importing/loaders.md | 2 +- gqlalchemy/transformations/importing/loaders.py | 14 +++++++------- tests/transformations/loaders/test_loaders.py | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/how-to-guides/loaders/import-table-data-to-graph-database.md b/docs/how-to-guides/loaders/import-table-data-to-graph-database.md index 08818f3a..bbaa692a 100644 --- a/docs/how-to-guides/loaders/import-table-data-to-graph-database.md +++ b/docs/how-to-guides/loaders/import-table-data-to-graph-database.md @@ -86,7 +86,7 @@ many_to_many_relations: # intended to be used in case of associative table reference_table: reference_key: label: # relationship's label - parameters: # list of parameters to add to the relationship + properties: # list of properties to add to the relationship ``` @@ -185,7 +185,7 @@ many_to_many_relations: reference_table: address reference_key: add_id label: LIVES_IN - parameters: + properties: - duration ``` diff --git a/docs/reference/gqlalchemy/transformations/importing/loaders.md b/docs/reference/gqlalchemy/transformations/importing/loaders.md index 1939098d..afb2262b 100644 --- a/docs/reference/gqlalchemy/transformations/importing/loaders.md +++ b/docs/reference/gqlalchemy/transformations/importing/loaders.md @@ -43,7 +43,7 @@ Many to many mapping is intended to be used in case of associative tables. - `foreign_key_from` - Describes the source of the relationship. - `foreign_key_to` - Describes the destination of the relationship. - `label` - Label to be applied to the newly created relationship. -- `parameters` - List of parameters that will be added to the relationship created from this object (Optional). +- `properties` - List of properties that will be added to the relationship created from this object (Optional). ## TableMapping Objects diff --git a/gqlalchemy/transformations/importing/loaders.py b/gqlalchemy/transformations/importing/loaders.py index c66e9b47..1664f353 100644 --- a/gqlalchemy/transformations/importing/loaders.py +++ b/gqlalchemy/transformations/importing/loaders.py @@ -113,13 +113,13 @@ class ManyToManyMapping: foreign_key_from: Describes the source of the relationship. foreign_key_to: Describes the destination of the relationship. label: Label to be applied to the newly created relationship. - parameters: Properties that will be added to the relationship created from this object (Optional). + properties: Properties that will be added to the relationship created from this object (Optional). """ foreign_key_from: ForeignKeyMapping foreign_key_to: ForeignKeyMapping label: str - parameters: Optional[List[str]] = None + properties: Optional[List[str]] = None Mapping = Union[List[OneToManyMapping], ManyToManyMapping] @@ -493,7 +493,7 @@ def _load_cross_relationships(self) -> None: property_to=mapping_to.reference_key, relation_label=many_to_many_mapping.mapping.label, table_name=many_to_many_mapping.table_name, - parameters=many_to_many_mapping.mapping.parameters, + properties=many_to_many_mapping.mapping.properties, row=row, ) @@ -607,7 +607,7 @@ def _save_row_as_relationship( property_to: str, relation_label: str, table_name: str, - parameters: List[str], + properties: List[str], row: Dict[str, Any], ) -> None: """Translates a row to a relationship and writes it to Memgraph. @@ -618,8 +618,8 @@ def _save_row_as_relationship( property_from: Property of the source node. property_to: Property of the destination node. relation_label: Label for the relationship. - table_name: Name of the table used to read parameters - parameters: Relationship parameters to be added + table_name: Name of the table used to read properties + properties: Relationship properties to be added row: The row to be translated. """ ( @@ -650,7 +650,7 @@ def _save_row_as_relationship( relationship_type=relation_label, **{ self._name_mapper.get_property_name(collection_name=table_name, column_name=prop): row[prop] - for prop in parameters + for prop in properties }, ) .node(variable=NODE_B) diff --git a/tests/transformations/loaders/test_loaders.py b/tests/transformations/loaders/test_loaders.py index 818bbfa7..09acf5f4 100644 --- a/tests/transformations/loaders/test_loaders.py +++ b/tests/transformations/loaders/test_loaders.py @@ -125,11 +125,11 @@ def test_local_table_to_graph_importer_csv(memgraph): conf_with_many_to_many = { "indices": {"address": ["add_id"], "individual": ["ind_id"]}, "name_mappings": { - "individual": {"label": "INDIVIDUAL"}, + "individual": {"label": "INDIVIDUAL"}, "address": {"label": "ADDRESS"}, "i2a": { "column_names_mapping": {"duration": "years"}, - } + }, }, "one_to_many_relations": {"address": [], "individual": []}, "many_to_many_relations": { @@ -141,7 +141,7 @@ def test_local_table_to_graph_importer_csv(memgraph): }, "foreign_key_to": {"column_name": "add_id", "reference_table": "address", "reference_key": "add_id"}, "label": "LIVES_IN", - "parameters": ["duration"] + "properties": ["duration"], } }, }