From 9bfd7fa7138d10364bd562b42c4edf401508daa0 Mon Sep 17 00:00:00 2001 From: Paul Prescod Date: Wed, 24 Mar 2021 16:21:33 -0700 Subject: [PATCH 1/3] Fix cases where some records have a record types and others don't --- snowfakery/salesforce.py | 2 +- tests/test_generate_mapping.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/snowfakery/salesforce.py b/snowfakery/salesforce.py index 2d454ed7..6ede9fa8 100644 --- a/snowfakery/salesforce.py +++ b/snowfakery/salesforce.py @@ -37,7 +37,7 @@ def _populate_rt_table(connection, table: Table, columnname: str, rt_table: Tabl query_res = connection.execute( select([column]).where(column is not None).distinct() ) - record_types = [res[0] for res in query_res] + record_types = [res[0] for res in query_res if res[0]] if record_types: insert_stmt = rt_table.insert() diff --git a/tests/test_generate_mapping.py b/tests/test_generate_mapping.py index cf017c35..7b886b2f 100644 --- a/tests/test_generate_mapping.py +++ b/tests/test_generate_mapping.py @@ -274,6 +274,20 @@ def test_Case_recordtypes(self, tmpdir, generate_in_tmpdir): assert records == [("Bar", "Bar")], records assert mapping["Insert Case"]["fields"]["RecordTypeId"] == "recordtype" + def test_incomplete_record_types(self, tmpdir, generate_in_tmpdir): + recipe_data = """ + - object: Case + fields: + recordtype: Bar + - object: Case + fields: + blah: Blah + """ + with generate_in_tmpdir(recipe_data) as (mapping, db): + records = list(db.execute("SELECT * from Case_rt_mapping")) + assert records == [("Bar", "Bar")], records + assert mapping["Insert Case"]["fields"]["RecordTypeId"] == "recordtype" + class TestPersonAccounts: def test_basic_person_accounts(self, generate_in_tmpdir): From cefdb35711a3ac3821011f93ec0a0715310b80a1 Mon Sep 17 00:00:00 2001 From: Paul Prescod Date: Tue, 30 Mar 2021 20:44:23 -0700 Subject: [PATCH 2/3] Remove unused file --- snowfakery/utils/collections.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 snowfakery/utils/collections.py diff --git a/snowfakery/utils/collections.py b/snowfakery/utils/collections.py deleted file mode 100644 index eb4bf6c1..00000000 --- a/snowfakery/utils/collections.py +++ /dev/null @@ -1,14 +0,0 @@ -class OrderedSet(dict): - """Simplistic ordered set. - - Other methods can be added later or we can swap it out for - a 3rd party version.""" - - def __init__(self, vals=()): - self.update(zip(vals, vals)) - - def add(self, val): - self[val] = val - - def remove(self, val): - del self[val] From b242e8464ec960ec0edf0bdd7c23690e15c8a35b Mon Sep 17 00:00:00 2001 From: Paul Prescod Date: Tue, 30 Mar 2021 23:01:09 -0700 Subject: [PATCH 3/3] Improve test coverage --- snowfakery/__init__.py | 4 +++- tests/cci/circular_references.yml | 18 ++++++++++++++++++ tests/cci/test_declaration_parser.py | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/cci/circular_references.yml diff --git a/snowfakery/__init__.py b/snowfakery/__init__.py index 9ee9616e..bfbe5df5 100644 --- a/snowfakery/__init__.py +++ b/snowfakery/__init__.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Tuple, Union, Optional, Dict, TextIO +from typing import Tuple, Union, Optional, Dict, TextIO, Sequence from contextlib import ExitStack from .plugins import SnowfakeryPlugin, lazy # noqa @@ -28,6 +28,7 @@ def generate_data( generate_continuation_file: Union[TextIO, Path] = None, generate_cci_mapping_file: Union[TextIO, Path] = None, should_create_cci_record_type_tables: bool = False, + load_declarations: Sequence[Union[Path, str]] = None ): from .cli import generate_cli @@ -66,4 +67,5 @@ def open_if_necessary_and_close_later(file_like, mode): generate_continuation_file=generate_continuation_file, generate_cci_mapping_file=generate_cci_mapping_file, should_create_cci_record_type_tables=should_create_cci_record_type_tables, + load_declarations=load_declarations, ) diff --git a/tests/cci/circular_references.yml b/tests/cci/circular_references.yml new file mode 100644 index 00000000..d41fb49d --- /dev/null +++ b/tests/cci/circular_references.yml @@ -0,0 +1,18 @@ +- object: Opportunity + fields: + Contact: + reference: Contact + Account: + reference: Account +- object: Contact + fields: + Account: + reference: Account + Opportunity: + reference: Opportunity +- object: Account + fields: + Contact: + reference: Contact + Opportunity: + reference: Opportunity diff --git a/tests/cci/test_declaration_parser.py b/tests/cci/test_declaration_parser.py index 4fb37e70..22baee04 100644 --- a/tests/cci/test_declaration_parser.py +++ b/tests/cci/test_declaration_parser.py @@ -1,7 +1,9 @@ from pathlib import Path +from io import StringIO from snowfakery.cci_mapping_files.declaration_parser import ( SObjectRuleDeclaration, + SObjectRuleDeclarationFile, unify, ) from snowfakery.cli import generate_cli @@ -138,3 +140,22 @@ def test_cli__multiple_files(self, tmpdir): assert map_data["Insert Account"]["api"] == "rest" assert map_data["Insert Contact"]["api"] == "rest" assert map_data["Insert Opportunity"]["api"] == "bulk" + + def test_circular_references__force_order(self, generate_in_tmpdir): + circular_test = (Path(__file__).parent / "circular_references.yml").read_text() + print(generate_in_tmpdir) + with generate_in_tmpdir( + circular_test, load_declarations=["tests/cci/mapping_mixins.load.yml"] + ) as (mapping, connection): + assert tuple(mapping.keys()) == tuple( + ["Insert Account", "Insert Contact", "Insert Opportunity"] + ) + + def test_parse_from_open_file(self): + s = StringIO( + """ + - sf_object: Foo + api: bulk + """ + ) + SObjectRuleDeclarationFile.parse_from_yaml(s)