From a3dbbf22aac9afb3ec9f98a00f95e8dc6ddc9031 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:49:33 -0800 Subject: [PATCH 01/12] quick debug logs --- data_diff/databases/base.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py index 8adea0b56..f59498cca 100644 --- a/data_diff/databases/base.py +++ b/data_diff/databases/base.py @@ -1031,11 +1031,14 @@ def enable_interactive(self): def select_table_schema(self, path: DbPath) -> str: """Provide SQL for selecting the table schema as (name, type, date_prec, num_prec)""" schema, name = self._normalize_table_path(path) + print(f"path: {path}") + print(f"schema: {schema}") + print(f"name: {name}") return ( "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale " "FROM information_schema.columns " - f"WHERE table_name = '{name}' AND table_schema = '{schema}'" + f"WHERE table_name = '{name}' AND table_schema = '{schema}' and table_catalog = '{schema}'" ) def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: @@ -1046,6 +1049,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: accessing the schema using a SQL query. """ rows = self.query(self.select_table_schema(path), list, log_message=path) + print(f"path: {path}") if not rows: raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns") @@ -1060,6 +1064,10 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: ) for r in rows } + print(f"d: {d}") + print(f"len(d): {len(d)}") + print(f"rows: {rows}") + print(f"len(rows): {len(rows)}") assert len(d) == len(rows) return d @@ -1160,7 +1168,7 @@ def _refine_coltypes( def _normalize_table_path(self, path: DbPath) -> DbPath: if len(path) == 1: return self.default_schema, path[0] - elif len(path) == 2: + else: return path raise ValueError(f"{self.name}: Bad table path for {self}: '{'.'.join(path)}'. Expected form: schema.table") From 8b31425cc6932805e15dba0e2f2877fb24d02263 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:55:10 -0800 Subject: [PATCH 02/12] fix the override method --- data_diff/databases/base.py | 5 +---- data_diff/databases/duckdb.py | 2 +- data_diff_demo | 1 + datafold-demo-sung | 1 + demo | 1 + 5 files changed, 5 insertions(+), 5 deletions(-) create mode 160000 data_diff_demo create mode 160000 datafold-demo-sung create mode 160000 demo diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py index f59498cca..d62c46bfd 100644 --- a/data_diff/databases/base.py +++ b/data_diff/databases/base.py @@ -1031,14 +1031,11 @@ def enable_interactive(self): def select_table_schema(self, path: DbPath) -> str: """Provide SQL for selecting the table schema as (name, type, date_prec, num_prec)""" schema, name = self._normalize_table_path(path) - print(f"path: {path}") - print(f"schema: {schema}") - print(f"name: {name}") return ( "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale " "FROM information_schema.columns " - f"WHERE table_name = '{name}' AND table_schema = '{schema}' and table_catalog = '{schema}'" + f"WHERE table_name = '{name}' AND table_schema = '{schema}'" ) def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index 4cdacde87..ceba19aa0 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -172,7 +172,7 @@ def select_table_schema(self, path: DbPath) -> str: return ( f"SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM {'.'.join(info_schema_path)} " - f"WHERE table_name = '{table}' AND table_schema = '{schema}'" + f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = '{database}'" ) def _normalize_table_path(self, path: DbPath) -> DbPath: diff --git a/data_diff_demo b/data_diff_demo new file mode 160000 index 000000000..d0784e8de --- /dev/null +++ b/data_diff_demo @@ -0,0 +1 @@ +Subproject commit d0784e8de9fc7958f91a599fa454be4f8b09c60d diff --git a/datafold-demo-sung b/datafold-demo-sung new file mode 160000 index 000000000..6ebfb06d1 --- /dev/null +++ b/datafold-demo-sung @@ -0,0 +1 @@ +Subproject commit 6ebfb06d1e0937309384cdb4955e6dbd23387256 diff --git a/demo b/demo new file mode 160000 index 000000000..3cf4d1195 --- /dev/null +++ b/demo @@ -0,0 +1 @@ +Subproject commit 3cf4d11956ebc0f000a62646deec88cdd321b3b4 From 887cd5b34db56c0ce329f924f37fc39c1a4d79ce Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:55:21 -0800 Subject: [PATCH 03/12] remove submods --- data_diff_demo | 1 - datafold-demo-sung | 1 - demo | 1 - 3 files changed, 3 deletions(-) delete mode 160000 data_diff_demo delete mode 160000 datafold-demo-sung delete mode 160000 demo diff --git a/data_diff_demo b/data_diff_demo deleted file mode 160000 index d0784e8de..000000000 --- a/data_diff_demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0784e8de9fc7958f91a599fa454be4f8b09c60d diff --git a/datafold-demo-sung b/datafold-demo-sung deleted file mode 160000 index 6ebfb06d1..000000000 --- a/datafold-demo-sung +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ebfb06d1e0937309384cdb4955e6dbd23387256 diff --git a/demo b/demo deleted file mode 160000 index 3cf4d1195..000000000 --- a/demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3cf4d11956ebc0f000a62646deec88cdd321b3b4 From ca375adfcf2f395bdd33fd76d83da54677b085ad Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:56:12 -0800 Subject: [PATCH 04/12] remove prints --- data_diff/databases/base.py | 7 ++----- data_diff_demo | 1 + datafold-demo-sung | 1 + demo | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) create mode 160000 data_diff_demo create mode 160000 datafold-demo-sung create mode 160000 demo diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py index d62c46bfd..6e6ac6058 100644 --- a/data_diff/databases/base.py +++ b/data_diff/databases/base.py @@ -1046,7 +1046,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: accessing the schema using a SQL query. """ rows = self.query(self.select_table_schema(path), list, log_message=path) - print(f"path: {path}") + if not rows: raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns") @@ -1061,10 +1061,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]: ) for r in rows } - print(f"d: {d}") - print(f"len(d): {len(d)}") - print(f"rows: {rows}") - print(f"len(rows): {len(rows)}") + assert len(d) == len(rows) return d diff --git a/data_diff_demo b/data_diff_demo new file mode 160000 index 000000000..d0784e8de --- /dev/null +++ b/data_diff_demo @@ -0,0 +1 @@ +Subproject commit d0784e8de9fc7958f91a599fa454be4f8b09c60d diff --git a/datafold-demo-sung b/datafold-demo-sung new file mode 160000 index 000000000..6ebfb06d1 --- /dev/null +++ b/datafold-demo-sung @@ -0,0 +1 @@ +Subproject commit 6ebfb06d1e0937309384cdb4955e6dbd23387256 diff --git a/demo b/demo new file mode 160000 index 000000000..3cf4d1195 --- /dev/null +++ b/demo @@ -0,0 +1 @@ +Subproject commit 3cf4d11956ebc0f000a62646deec88cdd321b3b4 From e36a778474443b5ac70e0970b3c60a3f8077f325 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:56:21 -0800 Subject: [PATCH 05/12] remove submods --- data_diff_demo | 1 - datafold-demo-sung | 1 - demo | 1 - 3 files changed, 3 deletions(-) delete mode 160000 data_diff_demo delete mode 160000 datafold-demo-sung delete mode 160000 demo diff --git a/data_diff_demo b/data_diff_demo deleted file mode 160000 index d0784e8de..000000000 --- a/data_diff_demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d0784e8de9fc7958f91a599fa454be4f8b09c60d diff --git a/datafold-demo-sung b/datafold-demo-sung deleted file mode 160000 index 6ebfb06d1..000000000 --- a/datafold-demo-sung +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ebfb06d1e0937309384cdb4955e6dbd23387256 diff --git a/demo b/demo deleted file mode 160000 index 3cf4d1195..000000000 --- a/demo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3cf4d11956ebc0f000a62646deec88cdd321b3b4 From a21feac0b43790e6db07b525c87821b410594a39 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Fri, 26 Jan 2024 11:56:51 -0800 Subject: [PATCH 06/12] revert change --- data_diff/databases/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py index 6e6ac6058..56e64076d 100644 --- a/data_diff/databases/base.py +++ b/data_diff/databases/base.py @@ -1162,7 +1162,7 @@ def _refine_coltypes( def _normalize_table_path(self, path: DbPath) -> DbPath: if len(path) == 1: return self.default_schema, path[0] - else: + elif len(path) == 2: return path raise ValueError(f"{self.name}: Bad table path for {self}: '{'.'.join(path)}'. Expected form: schema.table") From 979f5ec220c8bcbf9a0047c94a9a5c8219af34b9 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Thu, 1 Feb 2024 10:48:04 -0800 Subject: [PATCH 07/12] Refactor dynamic database clause in DuckDB.py --- data_diff/databases/duckdb.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index ceba19aa0..b7c95e881 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -167,12 +167,16 @@ def select_table_schema(self, path: DbPath) -> str: database, schema, table = self._normalize_table_path(path) info_schema_path = ["information_schema", "columns"] + if database: info_schema_path.insert(0, database) + dynamic_database_clause = f"'{database}'" + else: + dynamic_database_clause = "current_catalog()" return ( f"SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM {'.'.join(info_schema_path)} " - f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = '{database}'" + f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = {dynamic_database_clause}" ) def _normalize_table_path(self, path: DbPath) -> DbPath: From b1d05b281d3fe8d3e510d91747f1e5e2843b1d13 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Thu, 1 Feb 2024 11:39:08 -0800 Subject: [PATCH 08/12] draft tests --- data_diff/databases/duckdb.py | 2 +- tests/test_duckdb.py | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/test_duckdb.py diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index b7c95e881..9537ce50e 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -170,7 +170,7 @@ def select_table_schema(self, path: DbPath) -> str: if database: info_schema_path.insert(0, database) - dynamic_database_clause = f"'{database}'" + dynamic_database_clause = f"'{database}'" else: dynamic_database_clause = "current_catalog()" diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py new file mode 100644 index 000000000..84ac86911 --- /dev/null +++ b/tests/test_duckdb.py @@ -0,0 +1,46 @@ +import unittest +from data_diff.databases import duckdb as duckdb_differ +import os +import uuid + +test_duckdb_filepath = str(uuid.uuid4()) + ".duckdb" + + +class TestDuckDBTableSchemaMethods(unittest.TestCase): + def setUp(self): + # Create a new duckdb file + self.duckdb_conn = duckdb_differ.DuckDB(filepath=test_duckdb_filepath) + + def tearDown(self): + # Optional: delete file after tests + os.remove(test_duckdb_filepath) + + def test_normalize_table_path(self): + self.assertEqual(self.duckdb_conn._normalize_table_path(("test_table",)), (None, "main", "test_table")) + self.assertEqual( + self.duckdb_conn._normalize_table_path(("test_schema", "test_table")), (None, "test_schema", "test_table") + ) + self.assertEqual( + self.duckdb_conn._normalize_table_path(("test_database", "test_schema", "test_table")), + ("test_database", "test_schema", "test_table"), + ) + + with self.assertRaises(ValueError): + self.duckdb_conn._normalize_table_path(("test_database", "test_schema", "test_table", "extra")) + + def test_select_table_schema(self): + db_path = ("test_table",) + expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'main' and table_catalog = current_catalog()" + self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) + + db_path = ("custom_schema", "test_table") + expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = current_catalog()" + self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) + + db_path = ("custom_db", "custom_schema", "test_table") + expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM custom_db.information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = 'custom_db'" + self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) + + +if __name__ == "__main__": + unittest.main() From c09f9cf5ab96de7b1334517eb1dd3f90b2e57d12 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Thu, 1 Feb 2024 11:49:58 -0800 Subject: [PATCH 09/12] Add validation for input path in select_table_schema method --- data_diff/databases/duckdb.py | 5 +++++ tests/test_duckdb.py | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index 9537ce50e..a28115c01 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -166,6 +166,10 @@ def create_connection(self): def select_table_schema(self, path: DbPath) -> str: database, schema, table = self._normalize_table_path(path) + # If path only contains one object, raise an error + if len(path) == 1: + raise ValueError('The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table') + info_schema_path = ["information_schema", "columns"] if database: @@ -179,6 +183,7 @@ def select_table_schema(self, path: DbPath) -> str: f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = {dynamic_database_clause}" ) + def _normalize_table_path(self, path: DbPath) -> DbPath: if len(path) == 1: return None, self.default_schema, path[0] diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py index 84ac86911..7019efb2e 100644 --- a/tests/test_duckdb.py +++ b/tests/test_duckdb.py @@ -12,7 +12,6 @@ def setUp(self): self.duckdb_conn = duckdb_differ.DuckDB(filepath=test_duckdb_filepath) def tearDown(self): - # Optional: delete file after tests os.remove(test_duckdb_filepath) def test_normalize_table_path(self): @@ -29,9 +28,16 @@ def test_normalize_table_path(self): self.duckdb_conn._normalize_table_path(("test_database", "test_schema", "test_table", "extra")) def test_select_table_schema(self): - db_path = ("test_table",) - expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'main' and table_catalog = current_catalog()" - self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) + with self.assertRaises(ValueError) as context: + # Try to call the select_table_schema with only one value in the tuple + db_path = ("test_table",) + self.duckdb_conn.select_table_schema(db_path) + + # Check that the message in the ValueError is what you expect + self.assertTrue( + "The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table" + in str(context.exception) + ) db_path = ("custom_schema", "test_table") expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = current_catalog()" @@ -40,7 +46,3 @@ def test_select_table_schema(self): db_path = ("custom_db", "custom_schema", "test_table") expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM custom_db.information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = 'custom_db'" self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) - - -if __name__ == "__main__": - unittest.main() From 83f674bdf5e6019998e1fd0fe809f6a49f9d102e Mon Sep 17 00:00:00 2001 From: sungchun12 Date: Thu, 1 Feb 2024 19:50:21 +0000 Subject: [PATCH 10/12] style fixes by ruff --- data_diff/databases/duckdb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index a28115c01..68c299411 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -168,7 +168,9 @@ def select_table_schema(self, path: DbPath) -> str: # If path only contains one object, raise an error if len(path) == 1: - raise ValueError('The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table') + raise ValueError( + "The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table" + ) info_schema_path = ["information_schema", "columns"] @@ -183,7 +185,6 @@ def select_table_schema(self, path: DbPath) -> str: f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = {dynamic_database_clause}" ) - def _normalize_table_path(self, path: DbPath) -> DbPath: if len(path) == 1: return None, self.default_schema, path[0] From 0f491b25b8caf4f5b228ea3f48dded18238e7c1a Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Thu, 1 Feb 2024 11:51:28 -0800 Subject: [PATCH 11/12] Revert "Add validation for input path in select_table_schema method" This reverts commit c09f9cf5ab96de7b1334517eb1dd3f90b2e57d12. --- data_diff/databases/duckdb.py | 5 ----- tests/test_duckdb.py | 18 ++++++++---------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py index a28115c01..9537ce50e 100644 --- a/data_diff/databases/duckdb.py +++ b/data_diff/databases/duckdb.py @@ -166,10 +166,6 @@ def create_connection(self): def select_table_schema(self, path: DbPath) -> str: database, schema, table = self._normalize_table_path(path) - # If path only contains one object, raise an error - if len(path) == 1: - raise ValueError('The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table') - info_schema_path = ["information_schema", "columns"] if database: @@ -183,7 +179,6 @@ def select_table_schema(self, path: DbPath) -> str: f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = {dynamic_database_clause}" ) - def _normalize_table_path(self, path: DbPath) -> DbPath: if len(path) == 1: return None, self.default_schema, path[0] diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py index 7019efb2e..84ac86911 100644 --- a/tests/test_duckdb.py +++ b/tests/test_duckdb.py @@ -12,6 +12,7 @@ def setUp(self): self.duckdb_conn = duckdb_differ.DuckDB(filepath=test_duckdb_filepath) def tearDown(self): + # Optional: delete file after tests os.remove(test_duckdb_filepath) def test_normalize_table_path(self): @@ -28,16 +29,9 @@ def test_normalize_table_path(self): self.duckdb_conn._normalize_table_path(("test_database", "test_schema", "test_table", "extra")) def test_select_table_schema(self): - with self.assertRaises(ValueError) as context: - # Try to call the select_table_schema with only one value in the tuple - db_path = ("test_table",) - self.duckdb_conn.select_table_schema(db_path) - - # Check that the message in the ValueError is what you expect - self.assertTrue( - "The input path needs to have more than one object in your data diff configuration.\nExpected format: database.schema.table or schema.table" - in str(context.exception) - ) + db_path = ("test_table",) + expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'main' and table_catalog = current_catalog()" + self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) db_path = ("custom_schema", "test_table") expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = current_catalog()" @@ -46,3 +40,7 @@ def test_select_table_schema(self): db_path = ("custom_db", "custom_schema", "test_table") expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM custom_db.information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = 'custom_db'" self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) + + +if __name__ == "__main__": + unittest.main() From c4e5041034d3d68d85add3b7fa81633b0b06dd44 Mon Sep 17 00:00:00 2001 From: Sung Won Chung Date: Thu, 1 Feb 2024 11:56:54 -0800 Subject: [PATCH 12/12] Remove unnecessary code in test_duckdb.py --- tests/test_duckdb.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py index 84ac86911..10c3644e3 100644 --- a/tests/test_duckdb.py +++ b/tests/test_duckdb.py @@ -40,7 +40,3 @@ def test_select_table_schema(self): db_path = ("custom_db", "custom_schema", "test_table") expected_sql = "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale FROM custom_db.information_schema.columns WHERE table_name = 'test_table' AND table_schema = 'custom_schema' and table_catalog = 'custom_db'" self.assertEqual(self.duckdb_conn.select_table_schema(db_path), expected_sql) - - -if __name__ == "__main__": - unittest.main()