Skip to content

Commit 904065c

Browse files
mhauruIain-S
authored andcommitted
Default to null_provider for unrecognised column types, with warning
1 parent 059cdeb commit 904065c

File tree

6 files changed

+70
-6
lines changed

6 files changed

+70
-6
lines changed

sqlsynthgen/make.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,23 @@ def _get_provider_for_column(column: Column) -> Tuple[list[str], str, list[str]]
238238

239239
generator_function = mapping.get((column_type, column_size is not None), None)
240240

241+
# Try if we know how to generate for a superclass of this type.
241242
if not generator_function:
242243
for key, value in mapping.items():
243244
if issubclass(column_type, key[0]) and key[1] == (column_size is not None):
244245
generator_function = value
245246
break
246247

248+
# If we still don't have a generator, use null and warn.
247249
if not generator_function:
248-
raise ValueError(f"Unsupported SQLAlchemy type: {column_type}")
249-
250+
generator_function = "generic.null_provider.null"
251+
logger.warning(
252+
"Unsupported SQLAlchemy type %s for column %s. "
253+
"Setting this column to NULL always, "
254+
"you may want to configure a row generator for it instead.",
255+
column_type,
256+
column.name,
257+
)
250258
if column_size:
251259
generator_arguments.append(str(column_size))
252260

tests/examples/example_orm.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import List, Optional
1+
from typing import Any, List, Optional
22

33
from sqlalchemy import (
44
BigInteger,
@@ -18,6 +18,7 @@
1818
UniqueConstraint,
1919
Uuid,
2020
)
21+
from sqlalchemy.dialects.postgresql import CIDR
2122
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
2223
import datetime
2324

@@ -71,6 +72,14 @@ class Person(Base):
7172
)
7273

7374

75+
class StrangeTypeTable(Base):
76+
__tablename__ = "strange_type_table"
77+
__table_args__ = (PrimaryKeyConstraint("id", name="strange_type_table_pkey"),)
78+
79+
id: Mapped[int] = mapped_column(Integer, primary_key=True)
80+
column_with_unusual_type: Mapped[Optional[Any]] = mapped_column(CIDR)
81+
82+
7483
class UnignorableTable(Base):
7584
__tablename__ = "unignorable_table"
7685
__table_args__ = (PrimaryKeyConstraint("id", name="unignorable_table_pkey"),)

tests/examples/expected_ssg.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ def __call__(self, dst_db_conn):
9090
return result
9191

9292

93+
class strange_type_tableGenerator(TableGenerator):
94+
num_rows_per_pass = 1
95+
96+
def __init__(self):
97+
pass
98+
99+
def __call__(self, dst_db_conn):
100+
result = {}
101+
result["column_with_unusual_type"] = generic.null_provider.null()
102+
return result
103+
104+
93105
class unique_constraint_testGenerator(TableGenerator):
94106
num_rows_per_pass = 1
95107

@@ -188,6 +200,7 @@ def __call__(self, dst_db_conn):
188200
"data_type_test": data_type_testGenerator(),
189201
"no_pk_test": no_pk_testGenerator(),
190202
"person": personGenerator(),
203+
"strange_type_table": strange_type_tableGenerator(),
191204
"unique_constraint_test": unique_constraint_testGenerator(),
192205
"unique_constraint_test2": unique_constraint_test2Generator(),
193206
"test_entity": test_entityGenerator(),

tests/examples/src.dump

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@ CREATE TABLE public.table_to_be_ignored (
218218

219219
ALTER TABLE public.table_to_be_ignored OWNER TO postgres;
220220

221+
--
222+
-- Name: strange_type_table; Type: TABLE; Schema: public; Owner: postgres
223+
--
224+
225+
CREATE TABLE public.strange_type_table (
226+
id integer NOT NULL,
227+
column_with_unusual_type cidr
228+
);
229+
230+
ALTER TABLE public.strange_type_table OWNER TO postgres;
231+
221232
--
222233
-- Data for Name: concept; Type: TABLE DATA; Schema: public; Owner: postgres
223234
--
@@ -1390,6 +1401,13 @@ ALTER TABLE ONLY public.ref_to_unignorable_table
13901401
ALTER TABLE ONLY public.unignorable_table
13911402
ADD CONSTRAINT unignorable_table_pkey PRIMARY KEY (id);
13921403

1404+
--
1405+
-- Name: strange_type_table strange_type_table_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
1406+
--
1407+
1408+
ALTER TABLE ONLY public.strange_type_table
1409+
ADD CONSTRAINT strange_type_table_pkey PRIMARY KEY (id);
1410+
13931411
--
13941412
-- Name: fki_concept_concept_type_id_fkey; Type: INDEX; Schema: public; Owner: postgres
13951413
--

tests/test_functional.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ def test_workflow_minimal_args(self) -> None:
103103
# this could mean that we might accidentally violate the constraints. In
104104
# practice this won't happen because we only write one row to an empty table.
105105
self.assertEqual(
106+
"Unsupported SQLAlchemy type "
107+
"<class 'sqlalchemy.dialects.postgresql.types.CIDR'> "
108+
"for column column_with_unusual_type. "
109+
"Setting this column to NULL always, "
110+
"you may want to configure a row generator for it instead.\n"
106111
"A unique constraint (ab_uniq) isn't fully covered by one "
107112
"row generator (['a']). Enforcement of the constraint may not work.\n"
108113
"A unique constraint (ab_uniq) isn't fully covered by one "
@@ -257,7 +262,14 @@ def test_workflow_maximal_args(self) -> None:
257262
capture_output=True,
258263
env=self.env,
259264
)
260-
self.assertEqual("", completed_process.stderr.decode("utf-8"))
265+
self.assertEqual(
266+
"Unsupported SQLAlchemy type "
267+
"<class 'sqlalchemy.dialects.postgresql.types.CIDR'> "
268+
"for column column_with_unusual_type. "
269+
"Setting this column to NULL always, "
270+
"you may want to configure a row generator for it instead.\n",
271+
completed_process.stderr.decode("utf-8"),
272+
)
261273
self.assertSuccess(completed_process)
262274
self.assertEqual(
263275
f"Making {self.alt_ssg_file_path}.\n"
@@ -345,6 +357,7 @@ def test_workflow_maximal_args(self) -> None:
345357
"Generating data for table data_type_test\n"
346358
"Generating data for table no_pk_test\n"
347359
"Generating data for table person\n"
360+
"Generating data for table strange_type_table\n"
348361
"Generating data for table unique_constraint_test\n"
349362
"Generating data for table unique_constraint_test2\n"
350363
"Generating data for table test_entity\n"
@@ -358,6 +371,7 @@ def test_workflow_maximal_args(self) -> None:
358371
"Generating data for table data_type_test\n"
359372
"Generating data for table no_pk_test\n"
360373
"Generating data for table person\n"
374+
"Generating data for table strange_type_table\n"
361375
"Generating data for table unique_constraint_test\n"
362376
"Generating data for table unique_constraint_test2\n"
363377
"Generating data for table test_entity\n"
@@ -387,6 +401,7 @@ def test_workflow_maximal_args(self) -> None:
387401
"Truncating table test_entity\n"
388402
"Truncating table unique_constraint_test2\n"
389403
"Truncating table unique_constraint_test\n"
404+
"Truncating table strange_type_table\n"
390405
"Truncating table person\n"
391406
"Truncating table no_pk_test\n"
392407
"Truncating table data_type_test\n"

tests/test_remove.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ class RemoveTestCase(SSGTestCase):
1212

1313
@patch("sqlsynthgen.remove.get_settings", side_effect=get_test_settings)
1414
@patch("sqlsynthgen.remove.create_db_engine")
15-
@patch("sqlsynthgen.remove.delete", side_effect=range(1, 8))
15+
@patch("sqlsynthgen.remove.delete", side_effect=range(1, 9))
1616
def test_remove_db_data(
1717
self, mock_delete: MagicMock, mock_engine: MagicMock, _: MagicMock
1818
) -> None:
1919
"""Test the remove_db_data function."""
2020
config = {"tables": {"unignorable_table": {"ignore": True}}}
2121
remove_db_data(example_orm, remove_ssg, config)
22-
self.assertEqual(mock_delete.call_count, 7)
22+
self.assertEqual(mock_delete.call_count, 8)
2323
mock_delete.assert_has_calls(
2424
[
2525
call(example_orm.Base.metadata.tables[t])
@@ -29,6 +29,7 @@ def test_remove_db_data(
2929
"unique_constraint_test2",
3030
"unique_constraint_test",
3131
"person",
32+
"strange_type_table",
3233
"no_pk_test",
3334
"data_type_test",
3435
)

0 commit comments

Comments
 (0)