From 1aa3fd4a7bab2acf484949185bc55ca815f555fb Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 21 Nov 2023 13:34:35 -0700
Subject: [PATCH 01/99] add TIMESTAMP_NTZ for databricks

---
 data_diff/databases/databricks.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index 19a1f103b..bed17dea8 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -50,6 +50,7 @@ class Dialect(BaseDialect):
         "DECIMAL": Decimal,
         # Timestamps
         "TIMESTAMP": Timestamp,
+        "TIMESTAMP_NTZ": Timestamp,
         # Text
         "STRING": Text,
         # Boolean
@@ -89,7 +90,8 @@ def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
         """Databricks timestamp contains no more than 6 digits in precision"""
 
         if coltype.rounds:
-            timestamp = f"cast(round(unix_micros({value}) / 1000000, {coltype.precision}) * 1000000 as bigint)"
+            # cast to timestamp due to unix_micros() requiring timestamp
+            timestamp = f"cast(round(unix_micros(cast({value} as timestamp)) / 1000000, {coltype.precision}) * 1000000 as bigint)"
             return f"date_format(timestamp_micros({timestamp}), 'yyyy-MM-dd HH:mm:ss.SSSSSS')"
 
         precision_format = "S" * coltype.precision + "0" * (6 - coltype.precision)

From 7329c433302552d0943369a38d4b53576fb624fc Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 21 Nov 2023 14:16:44 -0700
Subject: [PATCH 02/99] v0.9.14

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index 1819ca0fd..0c999e58a 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.9.13"
+__version__ = "0.9.14"
diff --git a/pyproject.toml b/pyproject.toml
index e8952a5c3..34898f13f 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.9.13"
+version = "0.9.14"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From 2c3a305951bf33e7797890b97c6a86cb1e662e61 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 12:56:06 -0700
Subject: [PATCH 03/99] log schema as INFO

---
 data_diff/schema.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/schema.py b/data_diff/schema.py
index db17d287a..67b4261f1 100644
--- a/data_diff/schema.py
+++ b/data_diff/schema.py
@@ -9,7 +9,7 @@
 
 
 def create_schema(db_name: str, table_path: DbPath, schema: dict, case_sensitive: bool) -> CaseAwareMapping:
-    logger.debug(f"[{db_name}] Schema = {schema}")
+    logger.info(f"[{db_name}] Schema = {schema}")
 
     if case_sensitive:
         return CaseSensitiveDict(schema)

From 5a4b8794b47ba557b5435f3f2d0f71165bcef782 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 12:57:39 -0700
Subject: [PATCH 04/99] attempt to utilize information_schema in databricks

information_schema previously was not available
---
 data_diff/databases/databricks.py | 53 +++++++++++++++++++++----------
 1 file changed, 36 insertions(+), 17 deletions(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index bed17dea8..c3342c522 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -53,6 +53,7 @@ class Dialect(BaseDialect):
         "TIMESTAMP_NTZ": Timestamp,
         # Text
         "STRING": Text,
+        "VARCHAR": Text,
         # Boolean
         "BOOLEAN": Boolean,
     }
@@ -138,25 +139,43 @@ def create_connection(self):
             raise ConnectionError(*e.args) from e
 
     def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
-        # Databricks has INFORMATION_SCHEMA only for Databricks Runtime, not for Databricks SQL.
-        # https://docs.databricks.com/spark/latest/spark-sql/language-manual/information-schema/columns.html
-        # So, to obtain information about schema, we should use another approach.
-
         conn = self.create_connection()
+        table_schema = {}
 
-        catalog, schema, table = self._normalize_table_path(path)
-        with conn.cursor() as cursor:
-            cursor.columns(catalog_name=catalog, schema_name=schema, table_name=table)
-            try:
-                rows = cursor.fetchall()
-            finally:
-                conn.close()
-            if not rows:
-                raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
-
-            d = {r.COLUMN_NAME: (r.COLUMN_NAME, r.TYPE_NAME, r.DECIMAL_DIGITS, None, None) for r in rows}
-            assert len(d) == len(rows)
-            return d
+        try:
+            table_schema = super().query_table_schema(path)
+        except:
+            logging.warning("Failed to get schema from information_schema, falling back to legacy approach.")
+
+        if not table_schema:
+            catalog, schema, table = self._normalize_table_path(path)
+            with conn.cursor() as cursor:
+                cursor.columns(catalog_name=catalog, schema_name=schema, table_name=table)
+                try:
+                    rows = cursor.fetchall()
+                finally:
+                    conn.close()
+                if not rows:
+                    raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
+
+                table_schema = {r.COLUMN_NAME: (r.COLUMN_NAME, r.TYPE_NAME, r.DECIMAL_DIGITS, None, None) for r in rows}
+                assert len(table_schema) == len(rows)
+                return table_schema
+        else:
+            return table_schema
+
+    def select_table_schema(self, path: DbPath) -> str:
+        """Provide SQL for selecting the table schema as (name, type, date_prec, num_prec)"""
+        database, schema, name = self._normalize_table_path(path)
+        info_schema_path = ["information_schema", "columns"]
+        if database:
+            info_schema_path.insert(0, database)
+
+        return (
+            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale "
+            f"FROM {'.'.join(info_schema_path)} "
+            f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
+        )
 
     def _process_table_schema(
         self, path: DbPath, raw_schema: Dict[str, tuple], filter_columns: Sequence[str], where: str = None

From c9d1db00e44809a26aa7b8890d0f5f9ba8995499 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 12:59:07 -0700
Subject: [PATCH 05/99] redshift: normalize schema output

There are currently 3 possible mechanisms to get schema info for redshift.
Make sure their output conforms to the same pattern
---
 data_diff/databases/redshift.py | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index 7a621f578..ed2a61ace 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -121,16 +121,18 @@ def query_external_table_schema(self, path: DbPath) -> Dict[str, tuple]:
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
-        d = {r[0]: r for r in rows}
-        assert len(d) == len(rows)
-        return d
+        schema_dict = self._normalize_schema_info(rows)
+
+        return schema_dict
 
     def select_view_columns(self, path: DbPath) -> str:
         _, schema, table = self._normalize_table_path(path)
 
         return """select * from pg_get_cols('{}.{}')
-                cols(view_schema name, view_name name, col_name name, col_type varchar, col_num int)
-            """.format(schema, table)
+                cols(col_name name, col_type varchar)
+            """.format(
+            schema, table
+        )
 
     def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
         rows = self.query(self.select_view_columns(path), list)
@@ -138,10 +140,17 @@ def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
         if not rows:
             raise RuntimeError(f"{self.name}: View '{'.'.join(path)}' does not exist, or has no columns")
 
-        output = {}
+        schema_dict = self._normalize_schema_info(rows)
+
+        return schema_dict
+
+    # when using a non-information_schema source, strip (N) from type(N) etc. to match
+    # typical information_schema output
+    def _normalize_schema_info(self, rows) -> Dict[str, tuple]:
+        schema_dict = {}
         for r in rows:
-            col_name = r[2]
-            type_info = r[3].split("(")
+            col_name = r[0]
+            type_info = r[1].split("(")
             base_type = type_info[0]
             precision = None
             scale = None
@@ -153,9 +162,8 @@ def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
                     scale = int(scale)
 
             out = [col_name, base_type, None, precision, scale]
-            output[col_name] = tuple(out)
-
-        return output
+            schema_dict[col_name] = tuple(out)
+        return schema_dict
 
     def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
         try:

From 95968c53b46130d6ee01e854b137538af4ef589b Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 13:03:37 -0700
Subject: [PATCH 06/99] clarifying comment

---
 data_diff/databases/databricks.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index c3342c522..de5ea8b7b 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -148,6 +148,10 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
             logging.warning("Failed to get schema from information_schema, falling back to legacy approach.")
 
         if not table_schema:
+            # This legacy approach can cause bugs. e.g. VARCHAR(255) -> VARCHAR(255)
+            # and not the expected VARCHAR
+
+            # I don't think we'll fall back to this approach, but if so, see above
             catalog, schema, table = self._normalize_table_path(path)
             with conn.cursor() as cursor:
                 cursor.columns(catalog_name=catalog, schema_name=schema, table_name=table)

From 579b82cb858064a23c4241cf0094b8e2b3d72818 Mon Sep 17 00:00:00 2001
From: dlawin <dlawin@users.noreply.github.com>
Date: Wed, 22 Nov 2023 20:04:13 +0000
Subject: [PATCH 07/99] style fixes by ruff

---
 data_diff/databases/redshift.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index ed2a61ace..dcf061c43 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -130,9 +130,7 @@ def select_view_columns(self, path: DbPath) -> str:
 
         return """select * from pg_get_cols('{}.{}')
                 cols(col_name name, col_type varchar)
-            """.format(
-            schema, table
-        )
+            """.format(schema, table)
 
     def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
         rows = self.query(self.select_view_columns(path), list)

From 0c21e436294debf61b444e129948c2138344f5e0 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 13:50:23 -0700
Subject: [PATCH 08/99] v0.9.15

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index 0c999e58a..d2c526862 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.9.14"
+__version__ = "0.9.15"
diff --git a/pyproject.toml b/pyproject.toml
index 34898f13f..1e240c679 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.9.14"
+version = "0.9.15"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From 73331fcc5d78766462609f4cce89d684dfae5469 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 15:32:37 -0700
Subject: [PATCH 09/99] revert databricks information_schema

would need to update process_table_schema as well
---
 data_diff/databases/databricks.py | 69 ++++++++++++++-----------------
 1 file changed, 30 insertions(+), 39 deletions(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index de5ea8b7b..c755cfa9b 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -139,47 +139,38 @@ def create_connection(self):
             raise ConnectionError(*e.args) from e
 
     def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
+        # Databricks has INFORMATION_SCHEMA only for Databricks Runtime, not for Databricks SQL.
+        # https://docs.databricks.com/spark/latest/spark-sql/language-manual/information-schema/columns.html
+        # So, to obtain information about schema, we should use another approach.
+
         conn = self.create_connection()
-        table_schema = {}
 
-        try:
-            table_schema = super().query_table_schema(path)
-        except:
-            logging.warning("Failed to get schema from information_schema, falling back to legacy approach.")
-
-        if not table_schema:
-            # This legacy approach can cause bugs. e.g. VARCHAR(255) -> VARCHAR(255)
-            # and not the expected VARCHAR
-
-            # I don't think we'll fall back to this approach, but if so, see above
-            catalog, schema, table = self._normalize_table_path(path)
-            with conn.cursor() as cursor:
-                cursor.columns(catalog_name=catalog, schema_name=schema, table_name=table)
-                try:
-                    rows = cursor.fetchall()
-                finally:
-                    conn.close()
-                if not rows:
-                    raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
-
-                table_schema = {r.COLUMN_NAME: (r.COLUMN_NAME, r.TYPE_NAME, r.DECIMAL_DIGITS, None, None) for r in rows}
-                assert len(table_schema) == len(rows)
-                return table_schema
-        else:
-            return table_schema
-
-    def select_table_schema(self, path: DbPath) -> str:
-        """Provide SQL for selecting the table schema as (name, type, date_prec, num_prec)"""
-        database, schema, name = self._normalize_table_path(path)
-        info_schema_path = ["information_schema", "columns"]
-        if database:
-            info_schema_path.insert(0, database)
-
-        return (
-            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale "
-            f"FROM {'.'.join(info_schema_path)} "
-            f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
-        )
+        catalog, schema, table = self._normalize_table_path(path)
+        with conn.cursor() as cursor:
+            cursor.columns(catalog_name=catalog, schema_name=schema, table_name=table)
+            try:
+                rows = cursor.fetchall()
+            finally:
+                conn.close()
+            if not rows:
+                raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
+
+            d = {r.COLUMN_NAME: (r.COLUMN_NAME, r.TYPE_NAME, r.DECIMAL_DIGITS, None, None) for r in rows}
+            assert len(d) == len(rows)
+            return d
+
+    # def select_table_schema(self, path: DbPath) -> str:
+    #     """Provide SQL for selecting the table schema as (name, type, date_prec, num_prec)"""
+    #     database, schema, name = self._normalize_table_path(path)
+    #     info_schema_path = ["information_schema", "columns"]
+    #     if database:
+    #         info_schema_path.insert(0, database)
+
+    #     return (
+    #         "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale "
+    #         f"FROM {'.'.join(info_schema_path)} "
+    #         f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
+    #     )
 
     def _process_table_schema(
         self, path: DbPath, raw_schema: Dict[str, tuple], filter_columns: Sequence[str], where: str = None

From 767dbd502b5a710bd01dfef33ed40fe727d57fc3 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 22 Nov 2023 15:45:20 -0700
Subject: [PATCH 10/99] v0.9.16

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index d2c526862..0db237a6d 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.9.15"
+__version__ = "0.9.16"
diff --git a/pyproject.toml b/pyproject.toml
index 1e240c679..9394dd8ba 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.9.15"
+version = "0.9.16"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From 283bbac91bf213a49c668140b344b64cd622ae32 Mon Sep 17 00:00:00 2001
From: Chiel Fernhout <fernhoutchiel@gmail.com>
Date: Thu, 23 Nov 2023 21:36:23 +0100
Subject: [PATCH 11/99] Chiel fix link readme (#783)

* Add .history to .gitignore

* Fix README link to the correct documentation
---
 .gitignore | 3 +++
 README.md  | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index 2bc527158..644d7186d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -147,3 +147,6 @@ benchmark_*.png
 
 # VSCode
 .vscode
+
+# History
+.history
\ No newline at end of file
diff --git a/README.md b/README.md
index 7f04dec8c..fb422a472 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,7 @@ More information about the algorithm and performance considerations can be found
 # Get started
 
 ## Validating dbt model changes between dev and prod
-⚡ Looking to use `data-diff` in dbt development? Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/open_source/) to get started!
+⚡ Looking to use `data-diff` in dbt development? Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/how_it_works) to get started!
 
 ## Compare data tables between databases
 🔀 To compare data between databases, install `data-diff` with specific database adapters, e.g.:

From 5e60fc11afed946ad97c4f210af2da5a55c1c8de Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Thu, 30 Nov 2023 13:22:32 -0700
Subject: [PATCH 12/99] Handle full timestamp ranges for redshift postgres

---
 data_diff/databases/base.py       |  6 +++++
 data_diff/databases/postgresql.py | 37 ++++++++++++++++++++++++++-----
 data_diff/databases/redshift.py   | 20 -----------------
 3 files changed, 38 insertions(+), 25 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 871c650de..c59319790 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -800,6 +800,12 @@ def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
         Date format: ``YYYY-MM-DD HH:mm:SS.FFFFFF``
 
         Precision of dates should be rounded up/down according to coltype.rounds
+        e.g. precision 3 and coltype.rounds:
+            - 1969-12-31 23:59:59.999999 -> 1970-01-01 00:00:00.000000
+            - 1970-01-01 00:00:00.000888 -> 1970-01-01 00:00:00.001000
+            - 1970-01-01 00:00:00.123123 -> 1970-01-01 00:00:00.123000
+
+        Make sure NULLs remain NULLs
         """
 
     @abstractmethod
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 4b9e945f9..d29fa0eb5 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -102,13 +102,40 @@ def md5_as_hex(self, s: str) -> str:
         return f"md5({s})"
 
     def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
+        def _add_padding(coltype: TemporalType, timestamp6: str):
+            return f"RPAD(LEFT({timestamp6}, {TIMESTAMP_PRECISION_POS+coltype.precision}), {TIMESTAMP_PRECISION_POS+6}, '0')"
+
         if coltype.rounds:
-            return f"to_char({value}::timestamp({coltype.precision}), 'YYYY-mm-dd HH24:MI:SS.US')"
+            # NULL value expected to return NULL after normalization
+            null_case_begin = f"CASE WHEN {value} IS NULL THEN NULL ELSE "
+            null_case_end = "END"
+
+            # 294277 or 4714 BC would be out of range, make sure we can't round to that
+            # TODO test timezones for overflow?
+            max_timestamp = "294276-12-31 23:59:59.0000"
+            min_timestamp = "4713-01-01 00:00:00.00 BC"
+            timestamp = f"least('{max_timestamp}'::timestamp(6), {value}::timestamp(6))"
+            timestamp = f"greatest('{min_timestamp}'::timestamp(6), {timestamp})"
+
+            interval = format((0.5 * (10 ** (-coltype.precision))), f".{coltype.precision+1}f")
+
+            rounded_timestamp = (
+                f"left(to_char(least('{max_timestamp}'::timestamp, {timestamp})"
+                f"+ interval '{interval}', 'YYYY-mm-dd HH24:MI:SS.US'),"
+                f"length(to_char(least('{max_timestamp}'::timestamp, {timestamp})"
+                f"+ interval '{interval}', 'YYYY-mm-dd HH24:MI:SS.US')) - (6-{coltype.precision}))"
+            )
 
-        timestamp6 = f"to_char({value}::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
-        return (
-            f"RPAD(LEFT({timestamp6}, {TIMESTAMP_PRECISION_POS+coltype.precision}), {TIMESTAMP_PRECISION_POS+6}, '0')"
-        )
+            padded = _add_padding(coltype, rounded_timestamp)
+            return f"{null_case_begin} {padded} {null_case_end}"
+
+            # TODO years with > 4 digits not padded correctly
+            # current w/ precision 6: 294276-12-31 23:59:59.0000
+            # should be 294276-12-31 23:59:59.000000
+        else:
+            rounded_timestamp = f"to_char({value}::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
+            padded = _add_padding(coltype, rounded_timestamp)
+            return padded
 
     def normalize_number(self, value: str, coltype: FractionalType) -> str:
         return self.to_string(f"{value}::decimal(38, {coltype.precision})")
diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index dcf061c43..d31258e1d 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -51,26 +51,6 @@ def md5_as_int(self, s: str) -> str:
     def md5_as_hex(self, s: str) -> str:
         return f"md5({s})"
 
-    def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
-        if coltype.rounds:
-            timestamp = f"{value}::timestamp(6)"
-            # Get seconds since epoch. Redshift doesn't support milli- or micro-seconds.
-            secs = f"timestamp 'epoch' + round(extract(epoch from {timestamp})::decimal(38)"
-            # Get the milliseconds from timestamp.
-            ms = f"extract(ms from {timestamp})"
-            # Get the microseconds from timestamp, without the milliseconds!
-            us = f"extract(us from {timestamp})"
-            # epoch = Total time since epoch in microseconds.
-            epoch = f"{secs}*1000000 + {ms}*1000 + {us}"
-            timestamp6 = (
-                f"to_char({epoch}, -6+{coltype.precision}) * interval '0.000001 seconds', 'YYYY-mm-dd HH24:MI:SS.US')"
-            )
-        else:
-            timestamp6 = f"to_char({value}::timestamp(6), 'YYYY-mm-dd HH24:MI:SS.US')"
-        return (
-            f"RPAD(LEFT({timestamp6}, {TIMESTAMP_PRECISION_POS+coltype.precision}), {TIMESTAMP_PRECISION_POS+6}, '0')"
-        )
-
     def normalize_number(self, value: str, coltype: FractionalType) -> str:
         return self.to_string(f"{value}::decimal(38,{coltype.precision})")
 

From 4bf54553e8d6082efd8509dcde331af011293586 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Thu, 30 Nov 2023 13:53:40 -0700
Subject: [PATCH 13/99] databricks does not require "database"

---
 data_diff/dbt_config_validators.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/dbt_config_validators.py b/data_diff/dbt_config_validators.py
index 5258a0cac..e7c548a42 100644
--- a/data_diff/dbt_config_validators.py
+++ b/data_diff/dbt_config_validators.py
@@ -31,7 +31,7 @@ class DependsOn(BaseModel):
         resource_type: str
         name: str
         alias: str
-        database: str
+        database: Optional[str]
         schema_: str = Field(..., alias="schema")
         columns: Optional[Dict[str, Column]]
         meta: Dict[str, Any]

From 29b48b06110ca9e71a6e320eac429955b360f6de Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Thu, 30 Nov 2023 13:56:31 -0700
Subject: [PATCH 14/99] v0.9.17

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index 0db237a6d..e1170d35b 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.9.16"
+__version__ = "0.9.17"
diff --git a/pyproject.toml b/pyproject.toml
index 9394dd8ba..c3448c017 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.9.16"
+version = "0.9.17"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From b3d42237ddf79eea1b345f916380f588dcd25074 Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 6 Dec 2023 12:03:30 +1300
Subject: [PATCH 15/99] Make dbt data diffs concurrent (#776)

* v0 of concurrency

* concurrent logging

* remove todo

* remove todo

* better var name

* add node name to logger

* format string logs

* add optional logger param

* avoid extra threads

* use thread pools

* not multithreaded at the connection level anymore

* show errors as they happen

* show full stacktrace on error

* rearrange trace

* more logs for debugging

* update for threads mocking

* clear log params

* remove extra space

* remove long traceback

* Ensure log_message is optional

Co-authored-by: Dan Lawin <daniel@datafold.com>

* map threaded result to proper model id

* explicit type and optional

* rm submodules again

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
Co-authored-by: Dan Lawin <daniel@datafold.com>
---
 data_diff/databases/base.py  | 15 ++++++---
 data_diff/dbt.py             | 43 +++++++++++++++----------
 data_diff/dbt_parser.py      |  6 ++--
 data_diff/joindiff_tables.py | 61 +++++++++++++++++++++++++-----------
 data_diff/utils.py           | 28 ++++++++---------
 tests/test_dbt.py            | 21 ++++++++-----
 6 files changed, 110 insertions(+), 64 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index c59319790..bf1654617 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -931,7 +931,7 @@ def name(self):
     def compile(self, sql_ast):
         return self.dialect.compile(Compiler(self), sql_ast)
 
-    def query(self, sql_ast: Union[Expr, Generator], res_type: type = None):
+    def query(self, sql_ast: Union[Expr, Generator], res_type: type = None, log_message: Optional[str] = None):
         """Query the given SQL code/AST, and attempt to convert the result to type 'res_type'
 
         If given a generator, it will execute all the yielded sql queries with the same thread and cursor.
@@ -956,7 +956,10 @@ def query(self, sql_ast: Union[Expr, Generator], res_type: type = None):
                 if sql_code is SKIP:
                     return SKIP
 
-            logger.debug("Running SQL (%s):\n%s", self.name, sql_code)
+            if log_message:
+                logger.debug("Running SQL (%s): %s \n%s", self.name, log_message, sql_code)
+            else:
+                logger.debug("Running SQL (%s):\n%s", self.name, sql_code)
 
         if self._interactive and isinstance(sql_ast, Select):
             explained_sql = self.compile(Explain(sql_ast))
@@ -1022,7 +1025,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
         Note: This method exists instead of select_table_schema(), just because not all databases support
               accessing the schema using a SQL query.
         """
-        rows = self.query(self.select_table_schema(path), list)
+        rows = self.query(self.select_table_schema(path), list, log_message=path)
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
@@ -1044,7 +1047,7 @@ def query_table_unique_columns(self, path: DbPath) -> List[str]:
         """Query the table for its unique columns for table in 'path', and return {column}"""
         if not self.SUPPORTS_UNIQUE_CONSTAINT:
             raise NotImplementedError("This database doesn't support 'unique' constraints")
-        res = self.query(self.select_table_unique_columns(path), List[str])
+        res = self.query(self.select_table_unique_columns(path), List[str], log_message=path)
         return list(res)
 
     def _process_table_schema(
@@ -1086,7 +1089,9 @@ def _refine_coltypes(
         fields = [Code(self.dialect.normalize_uuid(self.dialect.quote(c), String_UUID())) for c in text_columns]
 
         samples_by_row = self.query(
-            table(*table_path).select(*fields).where(Code(where) if where else SKIP).limit(sample_size), list
+            table(*table_path).select(*fields).where(Code(where) if where else SKIP).limit(sample_size),
+            list,
+            log_message=table_path,
         )
         if not samples_by_row:
             raise ValueError(f"Table {table_path} is empty.")
diff --git a/data_diff/dbt.py b/data_diff/dbt.py
index bf36c4fcd..ef7804292 100644
--- a/data_diff/dbt.py
+++ b/data_diff/dbt.py
@@ -8,6 +8,7 @@
 import pydantic
 import rich
 from rich.prompt import Prompt
+from concurrent.futures import ThreadPoolExecutor, as_completed
 
 from data_diff.errors import (
     DataDiffCustomSchemaNoConfigError,
@@ -80,7 +81,6 @@ def dbt_diff(
     production_schema_flag: Optional[str] = None,
 ) -> None:
     print_version_info()
-    diff_threads = []
     set_entrypoint_name(os.getenv("DATAFOLD_TRIGGERED_BY", "CLI-dbt"))
     dbt_parser = DbtParser(profiles_dir_override, project_dir_override, state)
     models = dbt_parser.get_models(dbt_selection)
@@ -112,7 +112,11 @@ def dbt_diff(
     else:
         dbt_parser.set_connection()
 
-    with log_status_handler.status if log_status_handler else nullcontext():
+    futures = {}
+
+    with log_status_handler.status if log_status_handler else nullcontext(), ThreadPoolExecutor(
+        max_workers=dbt_parser.threads
+    ) as executor:
         for model in models:
             if log_status_handler:
                 log_status_handler.set_prefix(f"Diffing {model.alias} \n")
@@ -140,12 +144,12 @@ def dbt_diff(
 
             if diff_vars.primary_keys:
                 if is_cloud:
-                    diff_thread = run_as_daemon(
+                    future = executor.submit(
                         _cloud_diff, diff_vars, config.datasource_id, api, org_meta, log_status_handler
                     )
-                    diff_threads.append(diff_thread)
                 else:
-                    _local_diff(diff_vars, json_output)
+                    future = executor.submit(_local_diff, diff_vars, json_output, log_status_handler)
+                futures[future] = model
             else:
                 if json_output:
                     print(
@@ -165,10 +169,12 @@ def dbt_diff(
                         + "Skipped due to unknown primary key. Add uniqueness tests, meta, or tags.\n"
                     )
 
-        # wait for all threads
-        if diff_threads:
-            for thread in diff_threads:
-                thread.join()
+    for future in as_completed(futures):
+        model = futures[future]
+        try:
+            future.result()  # if error occurred, it will be raised here
+        except Exception as e:
+            logger.error(f"An error occurred during the execution of a diff task: {model.unique_id} - {e}")
 
     _extension_notification()
 
@@ -265,15 +271,17 @@ def _get_prod_path_from_manifest(model, prod_manifest) -> Union[Tuple[str, str,
     return prod_database, prod_schema, prod_alias
 
 
-def _local_diff(diff_vars: TDiffVars, json_output: bool = False) -> None:
+def _local_diff(
+    diff_vars: TDiffVars, json_output: bool = False, log_status_handler: Optional[LogStatusHandler] = None
+) -> None:
+    if log_status_handler:
+        log_status_handler.diff_started(diff_vars.dev_path[-1])
     dev_qualified_str = ".".join(diff_vars.dev_path)
     prod_qualified_str = ".".join(diff_vars.prod_path)
     diff_output_str = _diff_output_base(dev_qualified_str, prod_qualified_str)
 
-    table1 = connect_to_table(
-        diff_vars.connection, prod_qualified_str, tuple(diff_vars.primary_keys), diff_vars.threads
-    )
-    table2 = connect_to_table(diff_vars.connection, dev_qualified_str, tuple(diff_vars.primary_keys), diff_vars.threads)
+    table1 = connect_to_table(diff_vars.connection, prod_qualified_str, tuple(diff_vars.primary_keys))
+    table2 = connect_to_table(diff_vars.connection, dev_qualified_str, tuple(diff_vars.primary_keys))
 
     try:
         table1_columns = table1.get_schema()
@@ -373,6 +381,9 @@ def _local_diff(diff_vars: TDiffVars, json_output: bool = False) -> None:
         diff_output_str += no_differences_template()
         rich.print(diff_output_str)
 
+    if log_status_handler:
+        log_status_handler.diff_finished(diff_vars.dev_path[-1])
+
 
 def _initialize_api() -> Optional[DatafoldAPI]:
     datafold_host = os.environ.get("DATAFOLD_HOST")
@@ -406,7 +417,7 @@ def _cloud_diff(
     log_status_handler: Optional[LogStatusHandler] = None,
 ) -> None:
     if log_status_handler:
-        log_status_handler.cloud_diff_started(diff_vars.dev_path[-1])
+        log_status_handler.diff_started(diff_vars.dev_path[-1])
     diff_output_str = _diff_output_base(".".join(diff_vars.dev_path), ".".join(diff_vars.prod_path))
     payload = TCloudApiDataDiff(
         data_source1_id=datasource_id,
@@ -476,7 +487,7 @@ def _cloud_diff(
             rich.print(diff_output_str)
 
         if log_status_handler:
-            log_status_handler.cloud_diff_finished(diff_vars.dev_path[-1])
+            log_status_handler.diff_finished(diff_vars.dev_path[-1])
     except BaseException as ex:  # Catch KeyboardInterrupt too
         error = ex
     finally:
diff --git a/data_diff/dbt_parser.py b/data_diff/dbt_parser.py
index 4b6124d59..0d864a573 100644
--- a/data_diff/dbt_parser.py
+++ b/data_diff/dbt_parser.py
@@ -446,17 +446,17 @@ def get_pk_from_model(self, node, unique_columns: dict, pk_tag: str) -> List[str
 
             from_meta = [name for name, params in node.columns.items() if pk_tag in params.meta] or None
             if from_meta:
-                logger.debug("Found PKs via META: " + str(from_meta))
+                logger.debug(f"Found PKs via META [{node.name}]: " + str(from_meta))
                 return from_meta
 
             from_tags = [name for name, params in node.columns.items() if pk_tag in params.tags] or None
             if from_tags:
-                logger.debug("Found PKs via Tags: " + str(from_tags))
+                logger.debug(f"Found PKs via Tags [{node.name}]: " + str(from_tags))
                 return from_tags
             if node.unique_id in unique_columns:
                 from_uniq = unique_columns.get(node.unique_id)
                 if from_uniq is not None:
-                    logger.debug("Found PKs via Uniqueness tests: " + str(from_uniq))
+                    logger.debug(f"Found PKs via Uniqueness tests [{node.name}]: {str(from_uniq)}")
                     return list(from_uniq)
 
         except (KeyError, IndexError, TypeError) as e:
diff --git a/data_diff/joindiff_tables.py b/data_diff/joindiff_tables.py
index 6fadc5d85..8e7fcf303 100644
--- a/data_diff/joindiff_tables.py
+++ b/data_diff/joindiff_tables.py
@@ -162,7 +162,7 @@ def _diff_tables_root(self, table1: TableSegment, table2: TableSegment, info_tre
                 yield from self._diff_segments(None, table1, table2, info_tree, None)
             else:
                 yield from self._bisect_and_diff_tables(table1, table2, info_tree)
-            logger.info("Diffing complete")
+            logger.info(f"Diffing complete: {table1.table_path} <> {table2.table_path}")
             if self.materialize_to_table:
                 logger.info("Materialized diff to table '%s'.", ".".join(self.materialize_to_table))
 
@@ -193,8 +193,8 @@ def _diff_segments(
             partial(self._collect_stats, 1, table1, info_tree),
             partial(self._collect_stats, 2, table2, info_tree),
             partial(self._test_null_keys, table1, table2),
-            partial(self._sample_and_count_exclusive, db, diff_rows, a_cols, b_cols),
-            partial(self._count_diff_per_column, db, diff_rows, list(a_cols), is_diff_cols),
+            partial(self._sample_and_count_exclusive, db, diff_rows, a_cols, b_cols, table1, table2),
+            partial(self._count_diff_per_column, db, diff_rows, list(a_cols), is_diff_cols, table1, table2),
             partial(
                 self._materialize_diff,
                 db,
@@ -205,8 +205,8 @@ def _diff_segments(
             else None,
         ):
             assert len(a_cols) == len(b_cols)
-            logger.debug("Querying for different rows")
-            diff = db.query(diff_rows, list)
+            logger.debug(f"Querying for different rows: {table1.table_path}")
+            diff = db.query(diff_rows, list, log_message=table1.table_path)
             info_tree.info.set_diff(diff, schema=tuple(diff_rows.schema.items()))
             for is_xa, is_xb, *x in diff:
                 if is_xa and is_xb:
@@ -227,7 +227,7 @@ def _diff_segments(
                     yield "+", tuple(b_row)
 
     def _test_duplicate_keys(self, table1: TableSegment, table2: TableSegment):
-        logger.debug("Testing for duplicate keys")
+        logger.debug(f"Testing for duplicate keys: {table1.table_path} <> {table2.table_path}")
 
         # Test duplicate keys
         for ts in [table1, table2]:
@@ -240,16 +240,16 @@ def _test_duplicate_keys(self, table1: TableSegment, table2: TableSegment):
 
             unvalidated = list(set(key_columns) - set(unique))
             if unvalidated:
-                logger.info(f"Validating that the are no duplicate keys in columns: {unvalidated}")
+                logger.info(f"Validating that the are no duplicate keys in columns: {unvalidated} for {ts.table_path}")
                 # Validate that there are no duplicate keys
                 self.stats["validated_unique_keys"] = self.stats.get("validated_unique_keys", []) + [unvalidated]
                 q = t.select(total=Count(), total_distinct=Count(Concat(this[unvalidated]), distinct=True))
-                total, total_distinct = ts.database.query(q, tuple)
+                total, total_distinct = ts.database.query(q, tuple, log_message=ts.table_path)
                 if total != total_distinct:
                     raise ValueError("Duplicate primary keys")
 
     def _test_null_keys(self, table1, table2):
-        logger.debug("Testing for null keys")
+        logger.debug(f"Testing for null keys: {table1.table_path} <> {table2.table_path}")
 
         # Test null keys
         for ts in [table1, table2]:
@@ -257,7 +257,7 @@ def _test_null_keys(self, table1, table2):
             key_columns = ts.key_columns
 
             q = t.select(*this[key_columns]).where(or_(this[k] == None for k in key_columns))
-            nulls = ts.database.query(q, list)
+            nulls = ts.database.query(q, list, log_message=ts.table_path)
             if nulls:
                 if self.skip_null_keys:
                     logger.warning(
@@ -267,7 +267,7 @@ def _test_null_keys(self, table1, table2):
                     raise ValueError(f"NULL values in one or more primary keys of {ts.table_path}")
 
     def _collect_stats(self, i, table_seg: TableSegment, info_tree: InfoTree):
-        logger.debug(f"Collecting stats for table #{i}")
+        logger.debug(f"Collecting stats for table #{i}: {table_seg.table_path}")
         db = table_seg.database
 
         # Metrics
@@ -288,7 +288,7 @@ def _collect_stats(self, i, table_seg: TableSegment, info_tree: InfoTree):
         )
         col_exprs["count"] = Count()
 
-        res = db.query(table_seg.make_select().select(**col_exprs), tuple)
+        res = db.query(table_seg.make_select().select(**col_exprs), tuple, log_message=table_seg.table_path)
 
         for col_name, value in safezip(col_exprs, res):
             if value is not None:
@@ -303,7 +303,7 @@ def _collect_stats(self, i, table_seg: TableSegment, info_tree: InfoTree):
                 else:
                     self.stats[stat_name] = value
 
-        logger.debug("Done collecting stats for table #%s", i)
+        logger.debug("Done collecting stats for table #%s: %s", i, table_seg.table_path)
 
     def _create_outer_join(self, table1, table2):
         db = table1.database
@@ -334,23 +334,46 @@ def _create_outer_join(self, table1, table2):
         diff_rows = all_rows.where(or_(this[c] == 1 for c in is_diff_cols))
         return diff_rows, a_cols, b_cols, is_diff_cols, all_rows
 
-    def _count_diff_per_column(self, db, diff_rows, cols, is_diff_cols):
-        logger.debug("Counting differences per column")
-        is_diff_cols_counts = db.query(diff_rows.select(sum_(this[c]) for c in is_diff_cols), tuple)
+    def _count_diff_per_column(
+        self,
+        db,
+        diff_rows,
+        cols,
+        is_diff_cols,
+        table1: Optional[TableSegment] = None,
+        table2: Optional[TableSegment] = None,
+    ):
+        logger.info(type(table1))
+        logger.debug(f"Counting differences per column: {table1.table_path} <> {table2.table_path}")
+        is_diff_cols_counts = db.query(
+            diff_rows.select(sum_(this[c]) for c in is_diff_cols),
+            tuple,
+            log_message=f"{table1.table_path} <> {table2.table_path}",
+        )
         diff_counts = {}
         for name, count in safezip(cols, is_diff_cols_counts):
             diff_counts[name] = diff_counts.get(name, 0) + (count or 0)
         self.stats["diff_counts"] = diff_counts
 
-    def _sample_and_count_exclusive(self, db, diff_rows, a_cols, b_cols):
+    def _sample_and_count_exclusive(
+        self,
+        db,
+        diff_rows,
+        a_cols,
+        b_cols,
+        table1: Optional[TableSegment] = None,
+        table2: Optional[TableSegment] = None,
+    ):
         if isinstance(db, (Oracle, MsSQL)):
             exclusive_rows_query = diff_rows.where((this.is_exclusive_a == 1) | (this.is_exclusive_b == 1))
         else:
             exclusive_rows_query = diff_rows.where(this.is_exclusive_a | this.is_exclusive_b)
 
         if not self.sample_exclusive_rows:
-            logger.debug("Counting exclusive rows")
-            self.stats["exclusive_count"] = db.query(exclusive_rows_query.count(), int)
+            logger.debug(f"Counting exclusive rows: {table1.table_path} <> {table2.table_path}")
+            self.stats["exclusive_count"] = db.query(
+                exclusive_rows_query.count(), int, log_message=f"{table1.table_path} <> {table2.table_path}"
+            )
             return
 
         logger.info("Counting and sampling exclusive rows")
diff --git a/data_diff/utils.py b/data_diff/utils.py
index ee4a0f175..b9045cc13 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -485,31 +485,31 @@ def __init__(self):
         super().__init__()
         self.status = Status("")
         self.prefix = ""
-        self.cloud_diff_status = {}
+        self.diff_status = {}
 
     def emit(self, record):
         log_entry = self.format(record)
-        if self.cloud_diff_status:
-            self._update_cloud_status(log_entry)
+        if self.diff_status:
+            self._update_diff_status(log_entry)
         else:
             self.status.update(self.prefix + log_entry)
 
     def set_prefix(self, prefix_string):
         self.prefix = prefix_string
 
-    def cloud_diff_started(self, model_name):
-        self.cloud_diff_status[model_name] = "[yellow]In Progress[/]"
-        self._update_cloud_status()
+    def diff_started(self, model_name):
+        self.diff_status[model_name] = "[yellow]In Progress[/]"
+        self._update_diff_status()
 
-    def cloud_diff_finished(self, model_name):
-        self.cloud_diff_status[model_name] = "[green]Finished   [/]"
-        self._update_cloud_status()
+    def diff_finished(self, model_name):
+        self.diff_status[model_name] = "[green]Finished   [/]"
+        self._update_diff_status()
 
-    def _update_cloud_status(self, log=None):
-        cloud_status_string = "\n"
-        for model_name, status in self.cloud_diff_status.items():
-            cloud_status_string += f"{status} {model_name}\n"
-        self.status.update(f"{cloud_status_string}{log or ''}")
+    def _update_diff_status(self, log=None):
+        status_string = "\n"
+        for model_name, status in self.diff_status.items():
+            status_string += f"{status} {model_name}\n"
+        self.status.update(f"{status_string}{log or ''}")
 
 
 class UnknownMeta(type):
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index c281b6fbf..31af99ebb 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -93,8 +93,8 @@ def test_local_diff(self, mock_diff_tables):
         )
         self.assertEqual(len(mock_diff_tables.call_args[1]["extra_columns"]), 2)
         self.assertEqual(mock_connect.call_count, 2)
-        mock_connect.assert_any_call(connection, ".".join(dev_qualified_list), tuple(expected_primary_keys), threads)
-        mock_connect.assert_any_call(connection, ".".join(prod_qualified_list), tuple(expected_primary_keys), threads)
+        mock_connect.assert_any_call(connection, ".".join(dev_qualified_list), tuple(expected_primary_keys))
+        mock_connect.assert_any_call(connection, ".".join(prod_qualified_list), tuple(expected_primary_keys))
         mock_diff.get_stats_string.assert_called_once()
 
     @patch("data_diff.dbt.diff_tables")
@@ -180,8 +180,8 @@ def test_local_diff_no_diffs(self, mock_diff_tables):
         )
         self.assertEqual(len(mock_diff_tables.call_args[1]["extra_columns"]), 2)
         self.assertEqual(mock_connect.call_count, 2)
-        mock_connect.assert_any_call(connection, ".".join(dev_qualified_list), tuple(expected_primary_keys), None)
-        mock_connect.assert_any_call(connection, ".".join(prod_qualified_list), tuple(expected_primary_keys), None)
+        mock_connect.assert_any_call(connection, ".".join(dev_qualified_list), tuple(expected_primary_keys))
+        mock_connect.assert_any_call(connection, ".".join(prod_qualified_list), tuple(expected_primary_keys))
         mock_diff.get_stats_string.assert_not_called()
 
     @patch("data_diff.dbt.rich.print")
@@ -248,6 +248,7 @@ def test_diff_is_cloud(
         where = "a_string"
         config = TDatadiffConfig(prod_database="prod_db", prod_schema="prod_schema", datasource_id=1)
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_model = Mock()
         mock_api.get_data_source.return_value = TCloudApiDataSource(id=1, type="snowflake", name="snowflake")
         mock_initialize_api.return_value = mock_api
@@ -386,6 +387,7 @@ def test_diff_is_not_cloud(self, mock_print, mock_dbt_parser, mock_cloud_diff, m
         threads = None
         where = "a_string"
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_dbt_parser.return_value = mock_dbt_parser_inst
         mock_model = Mock()
         mock_dbt_parser_inst.get_models.return_value = [mock_model]
@@ -407,7 +409,7 @@ def test_diff_is_not_cloud(self, mock_print, mock_dbt_parser, mock_cloud_diff, m
         mock_dbt_parser_inst.get_models.assert_called_once()
         mock_dbt_parser_inst.set_connection.assert_called_once()
         mock_cloud_diff.assert_not_called()
-        mock_local_diff.assert_called_once_with(diff_vars, False)
+        mock_local_diff.assert_called_once_with(diff_vars, False, None)
         mock_print.assert_not_called()
 
     @patch("data_diff.dbt._get_diff_vars")
@@ -423,6 +425,7 @@ def test_diff_state_model_dne(
         threads = None
         where = "a_string"
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_dbt_parser.return_value = mock_dbt_parser_inst
         mock_model = Mock()
         mock_dbt_parser_inst.get_models.return_value = [mock_model]
@@ -460,6 +463,7 @@ def test_diff_only_prod_db(self, mock_print, mock_dbt_parser, mock_cloud_diff, m
         threads = None
         where = "a_string"
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_dbt_parser.return_value = mock_dbt_parser_inst
         mock_model = Mock()
         mock_dbt_parser_inst.get_models.return_value = [mock_model]
@@ -481,7 +485,7 @@ def test_diff_only_prod_db(self, mock_print, mock_dbt_parser, mock_cloud_diff, m
         mock_dbt_parser_inst.get_models.assert_called_once()
         mock_dbt_parser_inst.set_connection.assert_called_once()
         mock_cloud_diff.assert_not_called()
-        mock_local_diff.assert_called_once_with(diff_vars, False)
+        mock_local_diff.assert_called_once_with(diff_vars, False, None)
         mock_print.assert_not_called()
 
     @patch("data_diff.dbt._get_diff_vars")
@@ -497,6 +501,7 @@ def test_diff_only_prod_schema(
         threads = None
         where = "a_string"
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_dbt_parser.return_value = mock_dbt_parser_inst
         mock_model = Mock()
         mock_dbt_parser_inst.get_models.return_value = [mock_model]
@@ -518,7 +523,7 @@ def test_diff_only_prod_schema(
         mock_dbt_parser_inst.get_models.assert_called_once()
         mock_dbt_parser_inst.set_connection.assert_called_once()
         mock_cloud_diff.assert_not_called()
-        mock_local_diff.assert_called_once_with(diff_vars, False)
+        mock_local_diff.assert_called_once_with(diff_vars, False, None)
         mock_print.assert_not_called()
 
     @patch("data_diff.dbt._initialize_api")
@@ -543,6 +548,7 @@ def test_diff_is_cloud_no_pks(
         mock_model = Mock()
         connection = {}
         threads = None
+        mock_dbt_parser_inst.threads = threads
         where = "a_string"
         config = TDatadiffConfig(prod_database="prod_db", prod_schema="prod_schema", datasource_id=1)
         mock_api = Mock()
@@ -584,6 +590,7 @@ def test_diff_not_is_cloud_no_pks(
         threads = None
         where = "a_string"
         mock_dbt_parser_inst = Mock()
+        mock_dbt_parser_inst.threads = threads
         mock_dbt_parser.return_value = mock_dbt_parser_inst
         mock_model = Mock()
         mock_dbt_parser_inst.get_models.return_value = [mock_model]

From e61815bed9501df52620d7667f84106f3db3602e Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 5 Dec 2023 17:13:46 -0700
Subject: [PATCH 16/99] fix unreachable code branches

---
 data_diff/hashdiff_tables.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index b77594cc9..531213f4c 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -92,7 +92,7 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
             # Update schemas to minimal mutual precision
             col1 = table1._schema[c1]
             col2 = table2._schema[c2]
-            if isinstance(col1, PrecisionType) and isinstance(col2, PrecisionType):
+            if isinstance(col1, PrecisionType):
                 if strict and not isinstance(col2, PrecisionType):
                     raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
 
@@ -104,7 +104,7 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
                 table1._schema[c1] = attrs.evolve(col1, precision=lowest.precision, rounds=lowest.rounds)
                 table2._schema[c2] = attrs.evolve(col2, precision=lowest.precision, rounds=lowest.rounds)
 
-            elif isinstance(col1, (NumericType, Boolean)) and isinstance(col2, (NumericType, Boolean)):
+            elif isinstance(col1, (NumericType, Boolean)):
                 if strict and not isinstance(col2, (NumericType, Boolean)):
                     raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
 

From be1d947309ba8e5cefc5b1e47dae78dfe4df8d6e Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Wed, 6 Dec 2023 16:23:53 +0100
Subject: [PATCH 17/99] accept either key file path or file itself

---
 data_diff/databases/snowflake.py | 40 ++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 15 deletions(-)

diff --git a/data_diff/databases/snowflake.py b/data_diff/databases/snowflake.py
index d83c0f40f..5ab48243f 100644
--- a/data_diff/databases/snowflake.py
+++ b/data_diff/databases/snowflake.py
@@ -1,4 +1,5 @@
-from typing import Any, Union, List
+import base64
+from typing import Any, Union, List, Optional
 import logging
 
 import attrs
@@ -162,7 +163,7 @@ class Snowflake(Database):
 
     _conn: Any
 
-    def __init__(self, *, schema: str, **kw):
+    def __init__(self, *, schema: str, key: Optional[str] = None, key_content: Optional[str] = None, **kw):
         super().__init__()
         snowflake, serialization, default_backend = import_snowflake()
         logging.getLogger("snowflake.connector").setLevel(logging.WARNING)
@@ -172,20 +173,29 @@ def __init__(self, *, schema: str, **kw):
         logging.getLogger("snowflake.connector.network").disabled = True
 
         assert '"' not in schema, "Schema name should not contain quotes!"
+        if key_content and key:
+            raise ConnectError("Only key value or key file path can be specified, not both")
+
+        key_bytes = None
+        if key:
+            with open(key, "rb") as f:
+                key_bytes = f.read()
+        if key_content:
+            key_bytes = base64.b64decode(key_content)
+
         # If a private key is used, read it from the specified path and pass it as "private_key" to the connector.
-        if "key" in kw:
-            with open(kw.get("key"), "rb") as key:
-                if "password" in kw:
-                    raise ConnectError("Cannot use password and key at the same time")
-                if kw.get("private_key_passphrase"):
-                    encoded_passphrase = kw.get("private_key_passphrase").encode()
-                else:
-                    encoded_passphrase = None
-                p_key = serialization.load_pem_private_key(
-                    key.read(),
-                    password=encoded_passphrase,
-                    backend=default_backend(),
-                )
+        if key_bytes:
+            if "password" in kw:
+                raise ConnectError("Cannot use password and key at the same time")
+            if kw.get("private_key_passphrase"):
+                encoded_passphrase = kw.get("private_key_passphrase").encode()
+            else:
+                encoded_passphrase = None
+            p_key = serialization.load_pem_private_key(
+                key_bytes,
+                password=encoded_passphrase,
+                backend=default_backend(),
+            )
 
             kw["private_key"] = p_key.private_bytes(
                 encoding=serialization.Encoding.DER,

From bf7276b072938d29548f94e03df69d5f046f200b Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 6 Dec 2023 12:52:26 -0700
Subject: [PATCH 18/99] mssql normalize_uuid

---
 data_diff/databases/mssql.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index 8f5195ee1..b637c2858 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -13,6 +13,7 @@
 )
 from data_diff.abcs.database_types import (
     JSON,
+    ColType_UUID,
     NumericType,
     Timestamp,
     TimestampTZ,
@@ -154,6 +155,9 @@ def md5_as_int(self, s: str) -> str:
     def md5_as_hex(self, s: str) -> str:
         return f"HashBytes('MD5', {s})"
 
+    def normalize_uuid(self, value: str, coltype: ColType_UUID) -> str:
+        return f"TRIM(CAST({value} AS char)) AS {value}"
+
 
 @attrs.define(frozen=False, init=False, kw_only=True)
 class MsSQL(ThreadedDatabase):

From 8cfcb9b7d0e3611274c2cdd647c48afc611e3e23 Mon Sep 17 00:00:00 2001
From: Dan Lawin <daniellawin@gmail.com>
Date: Wed, 6 Dec 2023 16:10:36 -0700
Subject: [PATCH 19/99] Revert "mssql normalize_uuid"

---
 data_diff/databases/mssql.py | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index b637c2858..8f5195ee1 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -13,7 +13,6 @@
 )
 from data_diff.abcs.database_types import (
     JSON,
-    ColType_UUID,
     NumericType,
     Timestamp,
     TimestampTZ,
@@ -155,9 +154,6 @@ def md5_as_int(self, s: str) -> str:
     def md5_as_hex(self, s: str) -> str:
         return f"HashBytes('MD5', {s})"
 
-    def normalize_uuid(self, value: str, coltype: ColType_UUID) -> str:
-        return f"TRIM(CAST({value} AS char)) AS {value}"
-
 
 @attrs.define(frozen=False, init=False, kw_only=True)
 class MsSQL(ThreadedDatabase):

From 1ddd783091fba89d7496770db35cea0685a4149c Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 6 Dec 2023 16:13:59 -0700
Subject: [PATCH 20/99] fix mssql limit_select

---
 data_diff/databases/mssql.py | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index 8f5195ee1..d15e79543 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -113,19 +113,21 @@ def is_distinct_from(self, a: str, b: str) -> str:
     def limit_select(
         self,
         select_query: str,
-        offset: Optional[int] = None,
-        limit: Optional[int] = None,
-        has_order_by: Optional[bool] = None,
+        offset: int | None = None,
+        limit: int | None = None,
+        has_order_by: bool | None = None,
     ) -> str:
         if offset:
             raise NotImplementedError("No support for OFFSET in query")
-
         result = ""
         if not has_order_by:
             result += "ORDER BY 1"
 
         result += f" OFFSET 0 ROWS FETCH NEXT {limit} ROWS ONLY"
-        return f"SELECT * FROM ({select_query}) AS LIMITED_SELECT {result}"
+
+        # mssql requires that subquery columns are all aliased, so
+        # don't wrap in an outer select
+        return f"{select_query} {result}"
 
     def constant_values(self, rows) -> str:
         values = ", ".join("(%s)" % ", ".join(self._constant_value(v) for v in row) for row in rows)

From 643b1ea79cd5d63f03ce87e78de3646303394afa Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Wed, 6 Dec 2023 16:14:52 -0700
Subject: [PATCH 21/99] use Optional[]

---
 data_diff/databases/mssql.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index d15e79543..834ed9cd3 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -113,9 +113,9 @@ def is_distinct_from(self, a: str, b: str) -> str:
     def limit_select(
         self,
         select_query: str,
-        offset: int | None = None,
-        limit: int | None = None,
-        has_order_by: bool | None = None,
+        offset: Optional[int] = None,
+        limit: Optional[int] = None,
+        has_order_by: Optional[bool] = None,
     ) -> str:
         if offset:
             raise NotImplementedError("No support for OFFSET in query")

From 6906c42fffda9fbc737a8695b53cb85a8a8873f9 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Mon, 11 Dec 2023 11:59:06 -0700
Subject: [PATCH 22/99] v0.10.0rc0

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index e1170d35b..90ebae8a6 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.9.17"
+__version__ = "0.10.0rc0"
diff --git a/pyproject.toml b/pyproject.toml
index c3448c017..1b380ddee 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.9.17"
+version = "0.10.0rc0"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From c1dde755f7cae4048599d0f0d515f25a1e7d0b5b Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 13 Dec 2023 11:51:01 +1300
Subject: [PATCH 23/99] remove unneeded logging (#798)

Co-authored-by: Sung Won Chung <sung@datafold.com>
---
 data_diff/joindiff_tables.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/data_diff/joindiff_tables.py b/data_diff/joindiff_tables.py
index 8e7fcf303..2d5e631a2 100644
--- a/data_diff/joindiff_tables.py
+++ b/data_diff/joindiff_tables.py
@@ -343,7 +343,6 @@ def _count_diff_per_column(
         table1: Optional[TableSegment] = None,
         table2: Optional[TableSegment] = None,
     ):
-        logger.info(type(table1))
         logger.debug(f"Counting differences per column: {table1.table_path} <> {table2.table_path}")
         is_diff_cols_counts = db.query(
             diff_rows.select(sum_(this[c]) for c in is_diff_cols),

From 6c9ab5fdf68f19994a45ac6d7d90a8dfb743cc9a Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Fri, 15 Dec 2023 16:43:53 +0100
Subject: [PATCH 24/99] Accept external database types/schemes at runtime

---
 data_diff/databases/_connect.py | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/data_diff/databases/_connect.py b/data_diff/databases/_connect.py
index be55cc2da..1e34ef62b 100644
--- a/data_diff/databases/_connect.py
+++ b/data_diff/databases/_connect.py
@@ -26,7 +26,7 @@
 from data_diff.databases.mssql import MsSQL
 
 
-@attrs.define(frozen=True)
+@attrs.frozen
 class MatchUriPath:
     database_cls: Type[Database]
 
@@ -98,13 +98,11 @@ class Connect:
     """Provides methods for connecting to a supported database using a URL or connection dict."""
 
     database_by_scheme: Dict[str, Database]
-    match_uri_path: Dict[str, MatchUriPath]
     conn_cache: MutableMapping[Hashable, Database]
 
     def __init__(self, database_by_scheme: Dict[str, Database] = DATABASE_BY_SCHEME):
         super().__init__()
         self.database_by_scheme = database_by_scheme
-        self.match_uri_path = {name: MatchUriPath(cls) for name, cls in database_by_scheme.items()}
         self.conn_cache = weakref.WeakValueDictionary()
 
     def for_databases(self, *dbs) -> Self:
@@ -157,12 +155,10 @@ def connect_to_uri(self, db_uri: str, thread_count: Optional[int] = 1, **kwargs)
             return self.connect_with_dict(conn_dict, thread_count, **kwargs)
 
         try:
-            matcher = self.match_uri_path[scheme]
+            cls = self.database_by_scheme[scheme]
         except KeyError:
             raise NotImplementedError(f"Scheme '{scheme}' currently not supported")
 
-        cls = matcher.database_cls
-
         if scheme == "databricks":
             assert not dsn.user
             kw = {}
@@ -175,6 +171,7 @@ def connect_to_uri(self, db_uri: str, thread_count: Optional[int] = 1, **kwargs)
             kw["filepath"] = dsn.dbname
             kw["dbname"] = dsn.user
         else:
+            matcher = MatchUriPath(cls)
             kw = matcher.match_path(dsn)
 
             if scheme == "bigquery":
@@ -198,7 +195,7 @@ def connect_to_uri(self, db_uri: str, thread_count: Optional[int] = 1, **kwargs)
 
         kw = {k: v for k, v in kw.items() if v is not None}
 
-        if issubclass(cls, ThreadedDatabase):
+        if isinstance(cls, type) and issubclass(cls, ThreadedDatabase):
             db = cls(thread_count=thread_count, **kw, **kwargs)
         else:
             db = cls(**kw, **kwargs)
@@ -209,11 +206,10 @@ def connect_with_dict(self, d, thread_count, **kwargs):
         d = dict(d)
         driver = d.pop("driver")
         try:
-            matcher = self.match_uri_path[driver]
+            cls = self.database_by_scheme[driver]
         except KeyError:
             raise NotImplementedError(f"Driver '{driver}' currently not supported")
 
-        cls = matcher.database_cls
         if issubclass(cls, ThreadedDatabase):
             db = cls(thread_count=thread_count, **d, **kwargs)
         else:

From 3474795068ad561a48761e3e99e857b1e90c2ff6 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Fri, 15 Dec 2023 16:40:48 +0100
Subject: [PATCH 25/99] Tolerate empty samples for textual/uuid PKs

---
 data_diff/databases/base.py | 6 +-----
 tests/test_diff_tables.py   | 6 ++++--
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index bf1654617..059854a5f 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -1093,11 +1093,7 @@ def _refine_coltypes(
             list,
             log_message=table_path,
         )
-        if not samples_by_row:
-            raise ValueError(f"Table {table_path} is empty.")
-
-        samples_by_col = list(zip(*samples_by_row))
-
+        samples_by_col = list(zip(*samples_by_row)) if samples_by_row else [[]] * len(text_columns)
         for col_name, samples in safezip(text_columns, samples_by_col):
             uuid_samples = [s for s in samples if s and is_uuid(s)]
 
diff --git a/tests/test_diff_tables.py b/tests/test_diff_tables.py
index 2e48798a0..9a9750895 100644
--- a/tests/test_diff_tables.py
+++ b/tests/test_diff_tables.py
@@ -696,10 +696,12 @@ def setUp(self):
         self.differ = HashDiffer(bisection_factor=2)
 
     def test_right_table_empty(self):
-        self.assertRaises(ValueError, list, self.differ.diff_tables(self.a, self.b))
+        # NotImplementedError: Cannot use a column of type Text(_notes=[]) as a key
+        self.assertRaises(NotImplementedError, list, self.differ.diff_tables(self.a, self.b))
 
     def test_left_table_empty(self):
-        self.assertRaises(ValueError, list, self.differ.diff_tables(self.a, self.b))
+        # NotImplementedError: Cannot use a column of type Text(_notes=[]) as a key
+        self.assertRaises(NotImplementedError, list, self.differ.diff_tables(self.a, self.b))
 
 
 class TestInfoTree(DiffTestCase):

From f1ef90a17d9487fdb9d71ea77e6fd17c0345b004 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Fri, 15 Dec 2023 21:55:20 +0100
Subject: [PATCH 26/99] Tolerate column type mismatch, it could be aligned
 later & better

---
 data_diff/hashdiff_tables.py | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index b77594cc9..b9bf1239f 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -118,14 +118,6 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
                 if lowest.precision != col2.precision:
                     table2._schema[c2] = attrs.evolve(col2, precision=lowest.precision)
 
-            elif isinstance(col1, ColType_UUID):
-                if strict and not isinstance(col2, ColType_UUID):
-                    raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
-
-            elif isinstance(col1, StringType):
-                if strict and not isinstance(col2, StringType):
-                    raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
-
         for t in [table1, table2]:
             for c in t.relevant_columns:
                 ctype = t._schema[c]

From d45c3325208c929260855ded19caa9ddec66583b Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Fri, 15 Dec 2023 16:39:30 -0700
Subject: [PATCH 27/99] redshift: also try to get schema from svv_columns

---
 data_diff/databases/redshift.py | 37 ++++++++++++++++++++++++++++++++-
 1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index d31258e1d..44e86b17a 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -122,6 +122,38 @@ def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
 
         return schema_dict
 
+    def select_svv_columns_schema(self, path: DbPath) -> Dict[str, tuple]:
+        database, schema, table = self._normalize_table_path(path)
+
+        db_clause = ""
+        if database:
+            db_clause = f" AND table_catalog = '{database.lower()}'"
+
+        return (
+            f"""
+            select
+            	distinct
+                column_name,
+            	data_type,
+            	datetime_precision,
+            	numeric_precision,
+            	numeric_scale
+            from
+            	svv_columns
+            where table_name = '{table.lower()}' and table_schema = '{schema.lower()}'
+            """
+            + db_clause
+        )
+
+    def query_svv_columns(self, path: DbPath) -> Dict[str, tuple]:
+        rows = self.query(self.select_svv_columns_schema(path), list)
+        if not rows:
+            raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
+
+        d = {r[0]: r for r in rows}
+        assert len(d) == len(rows)
+        return d
+
     # when using a non-information_schema source, strip (N) from type(N) etc. to match
     # typical information_schema output
     def _normalize_schema_info(self, rows) -> Dict[str, tuple]:
@@ -150,7 +182,10 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
             try:
                 return self.query_external_table_schema(path)
             except RuntimeError:
-                return self.query_pg_get_cols(path)
+                try:
+                    return self.query_pg_get_cols(path)
+                except Exception:
+                    return self.query_svv_columns(path)
 
     def _normalize_table_path(self, path: DbPath) -> DbPath:
         if len(path) == 1:

From 0b7404617d20acf34c58503cdd30e2aa51933b4c Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Tue, 19 Dec 2023 11:25:29 +1300
Subject: [PATCH 28/99] Track data-diff usage in MotherDuck (#800)

* Update DuckDB connection parameters

* remove submods

* tracking logic

* conditional connection

* semver parsing

* motherduck test configs

* remove submods

* add motherduck dbt test

* passing motherduck tests

* more readable config

* remove submods

* user agent spec

* previous presto version

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
---
 .github/workflows/ci.yml                    |    1 +
 .github/workflows/ci_full.yml               |    1 +
 data_diff/databases/duckdb.py               |   16 +-
 poetry.lock                                 | 2020 ++++++++++---------
 pyproject.toml                              |    4 +-
 tests/dbt_artifacts/jaffle_shop.duckdb      |  Bin 4730880 -> 3158016 bytes
 tests/dbt_artifacts/motherduck/profiles.yml |    7 +
 tests/dbt_artifacts/profiles.yml            |    4 -
 tests/test_dbt.py                           |   18 +
 9 files changed, 1112 insertions(+), 959 deletions(-)
 create mode 100644 tests/dbt_artifacts/motherduck/profiles.yml

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fd995d5ab..acaaa597e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -68,6 +68,7 @@ jobs:
             DATADIFF_CLICKHOUSE_URI: 'clickhouse://clickhouse:Password1@localhost:9000/clickhouse'
             DATADIFF_VERTICA_URI: 'vertica://vertica:Password1@localhost:5433/vertica'
             DATADIFF_REDSHIFT_URI: '${{ secrets.DATADIFF_REDSHIFT_URI }}'
+            MOTHERDUCK_TOKEN: '${{ secrets.MOTHERDUCK_TOKEN }}'
         run: |
           chmod +x tests/waiting_for_stack_up.sh
           ./tests/waiting_for_stack_up.sh && TEST_ACROSS_ALL_DBS=0 poetry run unittest-parallel -j 16
diff --git a/.github/workflows/ci_full.yml b/.github/workflows/ci_full.yml
index d125d1142..3e17af0e4 100644
--- a/.github/workflows/ci_full.yml
+++ b/.github/workflows/ci_full.yml
@@ -64,6 +64,7 @@ jobs:
             DATADIFF_VERTICA_URI: 'vertica://vertica:Password1@localhost:5433/vertica'
             # DATADIFF_BIGQUERY_URI: '${{ secrets.DATADIFF_BIGQUERY_URI }}'
             DATADIFF_REDSHIFT_URI: '${{ secrets.DATADIFF_REDSHIFT_URI }}'
+            MOTHERDUCK_TOKEN: '${{ secrets.MOTHERDUCK_TOKEN }}'
         run: |
           chmod +x tests/waiting_for_stack_up.sh
           ./tests/waiting_for_stack_up.sh && poetry run unittest-parallel -j 16
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index 6c65b16b3..d057e0d90 100644
--- a/data_diff/databases/duckdb.py
+++ b/data_diff/databases/duckdb.py
@@ -1,6 +1,7 @@
 from typing import Any, ClassVar, Dict, Union, Type
 
 import attrs
+from packaging.version import parse as parse_version
 
 from data_diff.utils import match_regexps
 from data_diff.abcs.database_types import (
@@ -27,6 +28,7 @@
     CHECKSUM_OFFSET,
 )
 from data_diff.databases.base import MD5_HEXDIGITS, CHECKSUM_HEXDIGITS
+from data_diff.version import __version__
 
 
 @import_helper("duckdb")
@@ -148,9 +150,21 @@ def close(self):
     def create_connection(self):
         ddb = import_duckdb()
         try:
-            return ddb.connect(self._args["filepath"])
+            # custom_user_agent is only available in duckdb >= 0.9.2
+            if parse_version(ddb.__version__) >= parse_version("0.9.2"):
+                custom_user_agent = f"data-diff/v{__version__}"
+                config = {"custom_user_agent": custom_user_agent}
+                connection = ddb.connect(database=self._args["filepath"], config=config)
+                custom_user_agent_results = connection.sql("PRAGMA USER_AGENT;").fetchall()
+                custom_user_agent_filtered = custom_user_agent_results[0][0]
+                assert custom_user_agent in custom_user_agent_filtered
+            else:
+                connection = ddb.connect(database=self._args["filepath"])
+            return connection
         except ddb.OperationalError as e:
             raise ConnectError(*e.args) from e
+        except AssertionError:
+            raise ConnectError("Assertion failed: Custom user agent is invalid.") from None
 
     def select_table_schema(self, path: DbPath) -> str:
         database, schema, table = self._normalize_table_path(path)
diff --git a/poetry.lock b/poetry.lock
index 16e4495ce..e07c24027 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -25,17 +25,22 @@ test = ["PyICU (>=2.4.2)", "coverage (>=3.7.1)", "cssselect (>=0.9.1)", "lxml (>
 
 [[package]]
 name = "arrow"
-version = "1.2.3"
+version = "1.3.0"
 description = "Better dates & times for Python"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 files = [
-    {file = "arrow-1.2.3-py3-none-any.whl", hash = "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2"},
-    {file = "arrow-1.2.3.tar.gz", hash = "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1"},
+    {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"},
+    {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"},
 ]
 
 [package.dependencies]
 python-dateutil = ">=2.7.0"
+types-python-dateutil = ">=2.8.10"
+
+[package.extras]
+doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"]
+test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"]
 
 [[package]]
 name = "asn1crypto"
@@ -68,20 +73,23 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte
 
 [[package]]
 name = "babel"
-version = "2.11.0"
+version = "2.14.0"
 description = "Internationalization utilities"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"},
-    {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"},
+    {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"},
+    {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"},
 ]
 
 [package.dependencies]
-pytz = ">=2015.7"
+pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""}
+
+[package.extras]
+dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"]
 
 [[package]]
-name = "backports.zoneinfo"
+name = "backports-zoneinfo"
 version = "0.2.1"
 description = "Backport of the standard library zoneinfo module"
 optional = false
@@ -110,86 +118,74 @@ tzdata = ["tzdata"]
 
 [[package]]
 name = "certifi"
-version = "2022.12.7"
+version = "2023.11.17"
 description = "Python package for providing Mozilla's CA Bundle."
 optional = false
 python-versions = ">=3.6"
 files = [
-    {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
-    {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
+    {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"},
+    {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"},
 ]
 
 [[package]]
 name = "cffi"
-version = "1.15.1"
+version = "1.16.0"
 description = "Foreign Function Interface for Python calling C code."
 optional = false
-python-versions = "*"
+python-versions = ">=3.8"
 files = [
-    {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
-    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
-    {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
-    {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
-    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
-    {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
-    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
-    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
-    {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
-    {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
-    {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
-    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
-    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
-    {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
-    {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
-    {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
-    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
-    {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
-    {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
-    {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
-    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
-    {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
-    {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
-    {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
-    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
-    {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
-    {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
-    {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
-    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
-    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
-    {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
-    {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
-    {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
+    {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"},
+    {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"},
+    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"},
+    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"},
+    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"},
+    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"},
+    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"},
+    {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"},
+    {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"},
+    {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"},
+    {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"},
+    {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"},
+    {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"},
+    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"},
+    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"},
+    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"},
+    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"},
+    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"},
+    {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"},
+    {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"},
+    {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"},
+    {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"},
+    {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"},
+    {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"},
+    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"},
+    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"},
+    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"},
+    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"},
+    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"},
+    {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"},
+    {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"},
+    {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"},
+    {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"},
+    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"},
+    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"},
+    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"},
+    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"},
+    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"},
+    {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"},
+    {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"},
+    {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"},
+    {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"},
+    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"},
+    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"},
+    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"},
+    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"},
+    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"},
+    {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"},
+    {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"},
+    {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"},
+    {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"},
+    {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
 ]
 
 [package.dependencies]
@@ -208,27 +204,112 @@ files = [
 
 [[package]]
 name = "charset-normalizer"
-version = "2.0.12"
+version = "3.3.2"
 description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
 optional = false
-python-versions = ">=3.5.0"
-files = [
-    {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
-    {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
+python-versions = ">=3.7.0"
+files = [
+    {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
+    {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
+    {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
+    {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
+    {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
+    {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
+    {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
+    {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
 ]
 
-[package.extras]
-unicode-backport = ["unicodedata2"]
-
 [[package]]
 name = "click"
-version = "8.1.3"
+version = "8.1.7"
 description = "Composable command line interface toolkit"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
-    {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
+    {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+    {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
 ]
 
 [package.dependencies]
@@ -236,105 +317,92 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
 
 [[package]]
 name = "clickhouse-driver"
-version = "0.2.5"
+version = "0.2.6"
 description = "Python driver with native interface for ClickHouse"
 optional = false
-python-versions = ">=3.6, <4"
-files = [
-    {file = "clickhouse-driver-0.2.5.tar.gz", hash = "sha256:403239e5820d07d35a380f1abcd45ea0397fe8059984abf0594783d1474d56f5"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:413c7116a0f35bfc12c22f616b4cc9673d74b293c90361c748be03a987c753c4"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc7d48fc72ddb5a24c59b521c7ff56e7bcc8520a9b4afe50d7efaec1aa4ae616"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fbaef87d62bdf932c6d2f86c3a77d4675d309b9dd8c579b94776ec3da044bdf"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fda807b08ed23c6388c734486dcd218adefe78cac298f08dbc3a62d27d20462a"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2eb78e361ff0f4f45b694e2d08e58c00329ee512471b23f53a23815dc34660"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c70a2f0c8bd8165e63788aa64b583a2c92ff73ca0a07b60ef7980250cee24a3d"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:77c541961f29f17880bece8c5cf22f52564579c086fe859568189ccb36cef7cb"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3c0f5567e935b09ac6836e2a015306a6233538111be2a1067997fd7fdb865bed"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:36077623489c1558495cecfb682a777d33cb3f90b0d1e61558fe323d39cd736b"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ff24c5425b926eb18e434aa977f2ac1dfa6f907245fc1989633c07b67973843c"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d4fa637d702aca6993b5b03c20c910743e2a2e6a38661b8e9449b898d836b049"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-win32.whl", hash = "sha256:319c4ac6e063ca6786ca25aac86685841523d421f5483dc890589d221d36d562"},
-    {file = "clickhouse_driver-0.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:f0cb4b9b1dd316611e4de858eb82a4f70fd1807cce9919aeed5b7bfd320ca3dc"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4605f2f197c07c6db91b9636d29e50322f095b006b6aca0f5f958bbbfe3a4381"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc5543eb45e556a45ed57328446971ad3f786f8230fbb96d736ad51ca6a0f085"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ab396a5ad5c54d463bac1b268373b7977d076c3c7ec474fc5fc908629b7e989"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:758c3d0c09d6c23f9014045aeadf3a2620c3763fc0b2875a1a8e213092afb92b"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe9781724eaf2a0cd85a1f1b2906867d548399f4ecc6b8b7460f20410eb036b5"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aa79ddfb67ae2b6bf844d1493ab83321c4f2052686c6aa93f6658c737bd12"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8092518f839e01edbbe74db4c3d902028f9f4af5410571a131dac40f190edd4"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:019da690c9b82034ff7ebe2a2ac2af87b715a2c010f9a65fefc08c4bd792b0d6"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:fc300a72f0a09c2c286a55723466315a1b307f94a2ed81d1b7802598cd451059"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:937b663c400233d5ddd8b50fc260c3e374b7803dd401cb194ff64ddce9825aac"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e577b20814021e6851a7a3c075b1b4498c07ee5c1863481a6a1558a85739e145"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-win32.whl", hash = "sha256:d0d8f06a9264e1279c0aefc5dd7a6c6cdc4ce2d3aac3565865250db92694c9e7"},
-    {file = "clickhouse_driver-0.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:3a0741b32cf2ed019aba7c65e198d33a74d91b4ca67d5918860b7a32b7a5c158"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1edf78ff50587bde5775bfa98a17764d9fa2588e7841d63fadfca169277438d8"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e225d9261fbd35024b87b83c9d703331247d64583aedeb1210a700058422548e"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b5db4eccf1f9ff685b6a92b3755cfea612f58868c513344f71927697e93e7103"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b4fe92b120faae255354d6cf4a45639236583add948401e2b72600be793a1a"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85e1b9618dbd0772497556e7b6dcf8063191c0e2ea9d7ba8e447e70aea0a88c8"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02c540813d644f1de73b0c033c10671b6c2ce97b46a233ac1936d71cc527d48f"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d9d27f28fe2d3ca3e9ef995466b44ee7863de61a671e1e305853e235c4f4b36e"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:ee77062908490d111f65cc795cad9db2d3952630905f44ad17cb0b71374cffad"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:2a3e9d7dc9e58c7fee174516d00ad00b81fa6e4da56461d8ac206c28a16ad44c"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:d73c9dbc146d1456ea26c87f8b245f7ca69e5bc1883521fbc9074c3dd74a439a"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:14ce9ea8e4270307563bb95a1e39d8e9d6130cda926b33abbfb17d826b23acf0"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-win32.whl", hash = "sha256:d1cc49e8579b22d7fd2a8550b2da294bc21cc00189fa71ecf46b2f939011654c"},
-    {file = "clickhouse_driver-0.2.5-cp36-cp36m-win_amd64.whl", hash = "sha256:e6693c1ee9c6c248fe31db716f4f0bdeff84ea8f1b4262c4d941f58d4a3a58d5"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e1d7b6d22dd5efd771aa925a586185a51a64eeb908d61d5bfdcbb1416608d89"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20c8eb194897c7826d82aa67ac2f92496214cdac3a3713df5c48d94fff494593"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0631980b28267f1137b08e6982f244597c0809478edeaa9d6b8046f38e1369ed"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86c4b3bf77d3f81394b05dc4795485a95076bbe85708d14de261d7f961b0eff5"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:704a68cec8ce9997d2a8d43678852cbcc734b77fbe8c9b4b6c3aee9e09fed9ee"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8884f12911202c7b22502d1224cffb84559c91f93bcb1deb6a28251f7a82e98e"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:45852b9c90fa75a70c2a98556ad0a031a2a1c40e5bffe6dcf252c8cbace1f2b4"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:780843107ad370fdf1742aa68196158e395345ef72bb10f12a63ab82ea6f823d"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f8ceb503bacd0234d28c2e99ad61ca0d64d3282d8531c3607a3d7a849aedaf01"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:fd9116181a645c9393e5ef9287fc8747ce25ce5a1d8d8cf079223de8bdb00236"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:efcb67627233f377f6057388b88b9f68a98f06588da24d073166fed9b5e4e875"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-win32.whl", hash = "sha256:6876827eaf7b1c9711a54a1241cc7be9417ba4885c89e6dd49205417e870a261"},
-    {file = "clickhouse_driver-0.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:82835a6dca0016ac50d0b29eb02e9609f87f99af83e99fb0c5f15f893404c8bf"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e577d3e6d83cf71cf3dd29f5914448eb4d37adb61d9585a06642bd21c0b4bf6a"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e95ad1e7d8fa42b79b44a8fad5db1a92c6e09534f1a72209e0e6a00fdf2c148"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a61ec8e789f47933efb88c2d34af27e664a15f064d53411bfa2a56a34c1c8c39"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf671bac0d8f5e83736547c5ee3935ec859a77d5ce75cdfbbb5313e87cb3cb0b"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44f01d4a257b928e5981b8a0a0193c28a48ce3aed8b06f7a32f717ad2224836d"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bf7aad1d2b2c22dbccfaebcca55469558b0a754911b25e3a8506c4cc15cf01"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0e3762a866321af6a7ece560ed89c072e7bd6381fe642343e9d47c47ff191e23"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9f152bfe68af34468280f780b622a0c5dc0a5f19fd352542bf3491be4654cc13"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9954ca8b56e81f077d3f3845f88fabbf223eb4260b09691c3d957db7ff31f0d5"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5b011ee7340a73fda603e009f5f5463aabb4584d92aa93e96969908e9befb967"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ef2545823cfff38a61255651373b4705946accac38b5ffe817caaf9147a42ec4"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-win32.whl", hash = "sha256:0d1f4545e0de52774b512d943783529109b088b8716f16c75072a8af7b11ce22"},
-    {file = "clickhouse_driver-0.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:420b8be690e678c86ba57e446c98716598dc29a128759cc50bb1a6dc75e6b619"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b75463226330fd5d37bb2590f47cfa43c6694efffe516d598bd663b81a1d09dc"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f40176af385fc8d69e48a1e66d79349b0cdc05aeb83a45bc655d3fa5a7c6c36"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e2a0e059b5b2886c2ada313799dafddab5052f3f2209f0429cc738c3d7e55f8"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd78c78de4a74ac9fc3bcce3916b735539d34caaefb3c0fdcb39fea763078367"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70a70e46df56d966aed8423d5870a6b7f6137e20bb8ec2572723efb4bd1c80ca"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78062269ae40b9ba2d2f5bb4318c705d5b9543d268982f4fbf39f80f1325207c"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba975dbc89444ac69075007a97dfae5c7d51cd807372259e0051c723cc75fd21"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e61f72a6615477f3577714f5ba657be649e9c348a2d20864d16eb41b4446882d"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0254a800731469c00fa46d8f25cfab565703d07ae34ebe9bceb64ebfb0d8e99b"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:115abd0113e78dcc618b219c5539942792d121070b40f4e4b4bdbc03a23f6630"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c7311c46274f480f2bdc19d42151054eae8e3b9045624d4ca3182afd2fb7c5df"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-win32.whl", hash = "sha256:852b2d57890db87248c60f05809df3ce8a3737fc37b3908b23b6a914212cc2b9"},
-    {file = "clickhouse_driver-0.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:55f989eba98bfcf28da1dcbf4b7bb8322cd4a98df7855a68d4090160da2058a1"},
-    {file = "clickhouse_driver-0.2.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5f8585d6e1023779da471d37a3ea8623017f90115a85fef51d49a0c619010b44"},
-    {file = "clickhouse_driver-0.2.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59c07f648edbff11fdb5fc57f5d56f585acc0381bfda2cbbbc2ea04f6adf1767"},
-    {file = "clickhouse_driver-0.2.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd8e223a434fb7bffdd10e4541a3f756b58d15eac5e6bb701d0ad37719b20298"},
-    {file = "clickhouse_driver-0.2.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d092c89725c1c616ba9c1624a1ea5abbfc13d671ef2197b6c075b2d051f8bba2"},
-    {file = "clickhouse_driver-0.2.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f4587b47b8651f7c0576cfb374f318c758c420883fe8fbb97b2a6503ce525150"},
-    {file = "clickhouse_driver-0.2.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6083afaa4bb2691e42c588e635cc7bdfae3060d0a627e5a49f6bda2cb7bb3468"},
-    {file = "clickhouse_driver-0.2.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:585decb371c6b5cd3e9607c703925c49e96e7b872bbd676c71a0acf85397eeef"},
-    {file = "clickhouse_driver-0.2.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08aa10e63a911513fbe4ea7168a9fe2c55ce47693094e0e49d3db98ab1da9b1d"},
-    {file = "clickhouse_driver-0.2.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81c639203ae0c0491af6794dd88a7ee0329298cc76389e5475c89df732a649b4"},
-    {file = "clickhouse_driver-0.2.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5afb33e39d2ac0765e6e5014d57056bf1a783b7938a6d231eeeb049fe1967c27"},
-    {file = "clickhouse_driver-0.2.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:378d4a641842b891387d9a577eccbecdc0ac3dbafc29f7a6fa273cab2e3591f4"},
-    {file = "clickhouse_driver-0.2.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6321f328d79c1986706db57109ec80ac7c78b3782f261509e5441ba0ff8fce18"},
-    {file = "clickhouse_driver-0.2.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7ec4a6a8aba19c5b5945ad10ac45224a1203d00939d6382105f69c6367599ed"},
-    {file = "clickhouse_driver-0.2.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ac0d8c2f1d54fcca45393d6dbe40f0b11500ee07471671345361ca259ffd726"},
-    {file = "clickhouse_driver-0.2.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f380c0c7c598c22ed7c9ee0f6ecc133af959ba359999b09ec42dbbc97e7482dc"},
+python-versions = ">=3.7, <4"
+files = [
+    {file = "clickhouse-driver-0.2.6.tar.gz", hash = "sha256:028baf4d65a0b3f9e0ac5df248cab20657b51adbfce6c5427aa6c16a7318dda1"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e61d975081b74cae9efe7a64b1de1a8aec5643affb81b57487dcae7d195f250f"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d8aff4d3f0d78fd4b11e28ef344a5ee71d6850fef4a79e3265e0728b4d1d89"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b086bd658889af10205cb8307b714c8202bdfd05a4833fc7f4f82df2d88a963"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a1b6815d56a03398110c7f602a87ad767ecfd7a0869e61f2d8bfa0779dce2b"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36146fc3782a9e45a57c1094f3f8051db4117089502a3310312768dd7e14ef6d"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4032fb9b15ddbc484073ca165e5271eed494f3f3c4e8cb3a495bbc7a151fa556"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2e0332b4e4b68be0d5e97ee40cd3ce7f4f85523e3ea3656b4dda658ba723067"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7b659583fa2a8058dfeba952c0f17d5077b2af17db9c0f45ab8a5f9cf4dc1523"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:d4ce06dc2d2593bedade4bf369c28d7b0494532774e849f7213f800b06a274a2"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:3bf9071ca89f661ae7dd46f2561e7e97fe71fc96dbbaf0607afe636f173e5f40"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:429d9c16355aea62a462f75f373a2d9c4b76da7996a0eb6f038b2aa079020597"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1960244de84d7888598180e69689d1ba7ec6c9c99cd2c080a76315a7a29a5cab"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:5a6bdfde4e2fb81414200303950ba75c3f7ee9249e4a997854ce18e1cb4beea9"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef0a9453a972ec32399cc93a510aec33fa4b9b1f0c5050a3a40e5d298a89a7aa"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d715d392eaadb43ded1c104354aebbc233f69bbf3919aa61beb7cc6ecdaa950a"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d75d50265616a2779d0b2acaebf7253783e2b8ad0df3efa6d23f0db1c9bf50"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32f0e02c28e9a6f1c1f116d1aa14772e73beb7efd4f30490d9f171d39b40551a"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08037080bd7d1d2816767d1bc693380073ce8bdf4ad0f62871c12b77b90323a5"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cfe60ec8b695c298e6156c71a35ae6586676992cdfde6d2bf0c0b74414bfa0c"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:36ae6e627ffba6ed46fa9ac4dd745bfbfd5d9f39b198f46051ebfd0dde5e01c2"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2508638aa6f44cc0653840b99e308d3c0a8684c71e3132d7d067b160bdff5a81"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:88b77719e62aaa03a9d2d05e395788c4c112d41ff35a6756e7e7a1ac5dc1b4fb"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:95d1206252c6c9d0abad61310eda455ebcdcd0b1f41c3584daffbfd52b68654f"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3bdff826074af1b339fe9bff17844f6b8117080f895b8601f536b13a9d04f82a"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-win32.whl", hash = "sha256:c8c02606eabe4288045bbba497088b7fe976c34330c1066db9744fa09fef4a2a"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:44df94940739a72a02716bb14ac8b683aef84b54b05783d96201ff334bcd88fb"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f2a9abb8b1464985f7a480f956744736e611970ffc8ffd3eb0b46343a3a691e6"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e01696c450a2de41d586689dbaed0893d4de7469811abd3bf831a0483e723a"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0bb85760dabbef493aec985ad94612132ddeb5b81569cf0a7222f6cb7278eda"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26fa7c46a65beb6725e9d77701ed2871c8b3b7fd0c187c3c8550ae95e9886038"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c489cd1cf8b98f78e95559122c5b0d52f25b619cfd2ca31d0784a0bea38940b4"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af20ef3ddc7f834ebb316c349770f5c381354b573419523b9703ea48ed4bd692"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82538f76640cbd22540f9de301d996b1e48dbf5de71a79fc06826ea094c8e5f7"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:ccd34a5592f4212483138bea45dc6526c4cf7b5aa4b806f422b66d27232f7271"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:ab10bc9db2fbc0d5ab785c7771bfaac526ac6724b8727c2f0708caee878a6a48"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c9882ca5fd98b1801a283889e085e88c929fae1b68adc4e6b00ef1cf60adb843"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:051a1bd0f70a8d0bc11ef90b6e6291981cd8e3031cc126a7c78206849c1b8cf7"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:48f47694d5e54af192a4aa2a24f947795c362ab40a253d088593880fede97568"},
+    {file = "clickhouse_driver-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b783e5d3d12947c73d991bceb6b8765231512ab0ac6363823cdcd2c283c67a99"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d24e0acf8fef1d787851ae048e0168b2fb10297c3235cbb87974f78db37d3d3"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d534c744b1b211241f8c58d2ad5fcfc465a0503011d9b9073c00e25507abcbf3"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:858b8039a1241591b63f368de9dbdef6c4e6466b6bf0e01d53d36f7091af7569"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21eb62e1de7d2d5483d121d1447e857030bf866d4f23572b0dedc515f9359cd0"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eddbc4e90da8d3f08b5aa6c58a7155ebb398cc34255083e7103071b4c4a76952"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88f67ac3bf4cec39c051b33152bc1f370a3f0311774c73965727e14877e314fd"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:231ef65b7c99f2e937990b7072cf68bda6b51f45c903e5c8c068f7d754bdd489"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f4aadf85dc199f3d1ef06b961c87b168d009c88bfe431b4821460678d4ad51a9"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f08bc819a0c17b787c2984406611f5f2d9a8e33118090376c4bc8d932f38ea10"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ace862809bb89f896c2150e20ea6bbeb969c25ca40bfe389179469b0e0ec5dd7"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:512d2d5714e811dfc63eefdf5e0171f24a5e698134e684d8efe27c001fc3a06b"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-win32.whl", hash = "sha256:b9b775f70371a7333ac828fe2bbd9473c94e18728ac6b70b2865cdee1f0d551f"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:d13fe44620750abcd4c93c067d6e44c8a1ea050856c4c27a5633ad8ff197a689"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e17995752eef4f742976abab03ff3f5b81edb9b9218b151abaf3534055fcf2b8"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbd7e3e33d2bc5f32da2557e97299340a722f948790494a2e9efaed4635ff499"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c872e9fee17d278816fc30b4df4b10bedd8eec9efaa614c71725f147b00b30d"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c8af2761676cd306962a86cc87a4187efcfdaf253a0d908c8f8ef791277a7fe"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7ee63cf9443a94a0bc856ac947c9bfd8c214c12e340846f341391bb161cc4e"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3117c1bbcbec64a39c283ab2ff1ca284e57d5943b8e68e6f1df718ab04cb66e2"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9079621484b1f10017a65f7f84d81b13e44e9f23c5da1e04731405531bb63d58"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:aa73edc701635c5042c0355c8a0222eb03af117bebaf898017958d0e2cefb3b8"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:b5d9afcdec1fcc4e675fd25d31cd506b369efddc78d5e775804cfc911c773551"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6ad658e12e7c928283eb47f82fe4d36c8974918aabad1b3981212813fe21d03b"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:82fdc618428b31c418e6cdedfd66bd50b7662e2c092f685438bbe77e7f295f57"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-win32.whl", hash = "sha256:1736793aa273ebb71895eaa77ae4ab8ce361a28fc1cd5d92247f7af22a030c07"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:0efc58bf8b21a84b68bbba083702dc17cab5255d2552e73dacadc830b612bd38"},
+    {file = "clickhouse_driver-0.2.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5fdf175283918748e4821797e21cc0c91c44803e92698bd66f206769fb18da73"},
+    {file = "clickhouse_driver-0.2.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82c4145bf1531e4a508e187e5175e9c4d3749de5d98643141a348464360b8076"},
+    {file = "clickhouse_driver-0.2.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69c30943915b2ea794b8a85b8c2f6aa17dbf19a03cae1bc541c49b024f861200"},
+    {file = "clickhouse_driver-0.2.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45cfa76e7dadf097e77190dc27c23361cf2806ad646df979c657336e667af03e"},
+    {file = "clickhouse_driver-0.2.6-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d59c21e2d11e8e226ab1420a928f34be958301781dabc0176a8ae6e4d6dfa5b5"},
+    {file = "clickhouse_driver-0.2.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:07ab99b84510a88af3358a35deafa09942bdc26ad8213576af3f723e0cc11bb0"},
+    {file = "clickhouse_driver-0.2.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:712f9c313513898de98ac31e63aa2c0186f632d0490d6f2d010f259f35b9bf05"},
+    {file = "clickhouse_driver-0.2.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f2cb2fc81ee5c44068dd1d15a052a092cd6008de16d7e7850b1da7e29f316e"},
+    {file = "clickhouse_driver-0.2.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4bd0bf5fc48bf6317698714721fe5127c6ebc0d8ebd0ea14217bfd7d617303f5"},
+    {file = "clickhouse_driver-0.2.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b52e08b5ccf3a8ceca3727d0b4594c88e5b7876d5a17451d61ed78b158ada843"},
+    {file = "clickhouse_driver-0.2.6-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0081a4ac2fdb940c12dd74dd835323dfcda1e3df7cf178d9174f928fd28c1cfd"},
+    {file = "clickhouse_driver-0.2.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27eeb4f3cf5403dd2e8c6871c25dc129e5fc3dc6fb4ea125cd755be6476c6ff1"},
+    {file = "clickhouse_driver-0.2.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1ab6ce26455e4db46431fa75c6d6913e0ef91ac54ec8554ef9455e32d0090bb"},
+    {file = "clickhouse_driver-0.2.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36143db3bee3f16cc98ecda6df0110a5c6c479c69ec99fb2bb904a8f8139b64d"},
+    {file = "clickhouse_driver-0.2.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9fc3eacdcbc2ce5ca967c0e8dc74f2238fe9fd1bced50ea355580eebcc800dfd"},
 ]
 
 [package.dependencies]
@@ -348,86 +416,74 @@ zstd = ["clickhouse-cityhash (>=1.0.2.1)", "zstd"]
 
 [[package]]
 name = "colorama"
-version = "0.4.4"
+version = "0.4.6"
 description = "Cross-platform colored terminal text."
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-files = [
-    {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
-    {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
-]
-
-[[package]]
-name = "commonmark"
-version = "0.9.1"
-description = "Python parser for the CommonMark Markdown spec"
-optional = false
-python-versions = "*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 files = [
-    {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
-    {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
+    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 ]
 
-[package.extras]
-test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
-
 [[package]]
 name = "coverage"
-version = "6.5.0"
+version = "7.3.3"
 description = "Code coverage measurement for Python"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"},
-    {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"},
-    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"},
-    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"},
-    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"},
-    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"},
-    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"},
-    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"},
-    {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"},
-    {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"},
-    {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"},
-    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"},
-    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"},
-    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"},
-    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"},
-    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"},
-    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"},
-    {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"},
-    {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"},
-    {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"},
-    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"},
-    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"},
-    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"},
-    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"},
-    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"},
-    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"},
-    {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"},
-    {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"},
-    {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"},
-    {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"},
-    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"},
-    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"},
-    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"},
-    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"},
-    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"},
-    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"},
-    {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"},
-    {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"},
-    {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"},
-    {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"},
-    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"},
-    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"},
-    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"},
-    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"},
-    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"},
-    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"},
-    {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"},
-    {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"},
-    {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"},
-    {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"},
+    {file = "coverage-7.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d874434e0cb7b90f7af2b6e3309b0733cde8ec1476eb47db148ed7deeb2a9494"},
+    {file = "coverage-7.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6621dccce8af666b8c4651f9f43467bfbf409607c604b840b78f4ff3619aeb"},
+    {file = "coverage-7.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1367aa411afb4431ab58fd7ee102adb2665894d047c490649e86219327183134"},
+    {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f0f8f0c497eb9c9f18f21de0750c8d8b4b9c7000b43996a094290b59d0e7523"},
+    {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0338c4b0951d93d547e0ff8d8ea340fecf5885f5b00b23be5aa99549e14cfd"},
+    {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d31650d313bd90d027f4be7663dfa2241079edd780b56ac416b56eebe0a21aab"},
+    {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9437a4074b43c177c92c96d051957592afd85ba00d3e92002c8ef45ee75df438"},
+    {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e17d9cb06c13b4f2ef570355fa45797d10f19ca71395910b249e3f77942a837"},
+    {file = "coverage-7.3.3-cp310-cp310-win32.whl", hash = "sha256:eee5e741b43ea1b49d98ab6e40f7e299e97715af2488d1c77a90de4a663a86e2"},
+    {file = "coverage-7.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:593efa42160c15c59ee9b66c5f27a453ed3968718e6e58431cdfb2d50d5ad284"},
+    {file = "coverage-7.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c944cf1775235c0857829c275c777a2c3e33032e544bcef614036f337ac37bb"},
+    {file = "coverage-7.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eda7f6e92358ac9e1717ce1f0377ed2b9320cea070906ece4e5c11d172a45a39"},
+    {file = "coverage-7.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c854c1d2c7d3e47f7120b560d1a30c1ca221e207439608d27bc4d08fd4aeae8"},
+    {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:222b038f08a7ebed1e4e78ccf3c09a1ca4ac3da16de983e66520973443b546bc"},
+    {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4800783d85bff132f2cc7d007426ec698cdce08c3062c8d501ad3f4ea3d16c"},
+    {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fc200cec654311ca2c3f5ab3ce2220521b3d4732f68e1b1e79bef8fcfc1f2b97"},
+    {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:307aecb65bb77cbfebf2eb6e12009e9034d050c6c69d8a5f3f737b329f4f15fb"},
+    {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ffb0eacbadb705c0a6969b0adf468f126b064f3362411df95f6d4f31c40d31c1"},
+    {file = "coverage-7.3.3-cp311-cp311-win32.whl", hash = "sha256:79c32f875fd7c0ed8d642b221cf81feba98183d2ff14d1f37a1bbce6b0347d9f"},
+    {file = "coverage-7.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:243576944f7c1a1205e5cd658533a50eba662c74f9be4c050d51c69bd4532936"},
+    {file = "coverage-7.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a2ac4245f18057dfec3b0074c4eb366953bca6787f1ec397c004c78176a23d56"},
+    {file = "coverage-7.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9191be7af41f0b54324ded600e8ddbcabea23e1e8ba419d9a53b241dece821d"},
+    {file = "coverage-7.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c0b1b8b5a4aebf8fcd227237fc4263aa7fa0ddcd4d288d42f50eff18b0bac4"},
+    {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee453085279df1bac0996bc97004771a4a052b1f1e23f6101213e3796ff3cb85"},
+    {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1191270b06ecd68b1d00897b2daddb98e1719f63750969614ceb3438228c088e"},
+    {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007a7e49831cfe387473e92e9ff07377f6121120669ddc39674e7244350a6a29"},
+    {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:af75cf83c2d57717a8493ed2246d34b1f3398cb8a92b10fd7a1858cad8e78f59"},
+    {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:811ca7373da32f1ccee2927dc27dc523462fd30674a80102f86c6753d6681bc6"},
+    {file = "coverage-7.3.3-cp312-cp312-win32.whl", hash = "sha256:733537a182b5d62184f2a72796eb6901299898231a8e4f84c858c68684b25a70"},
+    {file = "coverage-7.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:e995efb191f04b01ced307dbd7407ebf6e6dc209b528d75583277b10fd1800ee"},
+    {file = "coverage-7.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbd8a5fe6c893de21a3c6835071ec116d79334fbdf641743332e442a3466f7ea"},
+    {file = "coverage-7.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:50c472c1916540f8b2deef10cdc736cd2b3d1464d3945e4da0333862270dcb15"},
+    {file = "coverage-7.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e9223a18f51d00d3ce239c39fc41410489ec7a248a84fab443fbb39c943616c"},
+    {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f501e36ac428c1b334c41e196ff6bd550c0353c7314716e80055b1f0a32ba394"},
+    {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:475de8213ed95a6b6283056d180b2442eee38d5948d735cd3d3b52b86dd65b92"},
+    {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afdcc10c01d0db217fc0a64f58c7edd635b8f27787fea0a3054b856a6dff8717"},
+    {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fff0b2f249ac642fd735f009b8363c2b46cf406d3caec00e4deeb79b5ff39b40"},
+    {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a1f76cfc122c9e0f62dbe0460ec9cc7696fc9a0293931a33b8870f78cf83a327"},
+    {file = "coverage-7.3.3-cp38-cp38-win32.whl", hash = "sha256:757453848c18d7ab5d5b5f1827293d580f156f1c2c8cef45bfc21f37d8681069"},
+    {file = "coverage-7.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad2453b852a1316c8a103c9c970db8fbc262f4f6b930aa6c606df9b2766eee06"},
+    {file = "coverage-7.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b15e03b8ee6a908db48eccf4e4e42397f146ab1e91c6324da44197a45cb9132"},
+    {file = "coverage-7.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89400aa1752e09f666cc48708eaa171eef0ebe3d5f74044b614729231763ae69"},
+    {file = "coverage-7.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c59a3e59fb95e6d72e71dc915e6d7fa568863fad0a80b33bc7b82d6e9f844973"},
+    {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ede881c7618f9cf93e2df0421ee127afdfd267d1b5d0c59bcea771cf160ea4a"},
+    {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bfd2c2f0e5384276e12b14882bf2c7621f97c35320c3e7132c156ce18436a1"},
+    {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f3bad1a9313401ff2964e411ab7d57fb700a2d5478b727e13f156c8f89774a0"},
+    {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:65d716b736f16e250435473c5ca01285d73c29f20097decdbb12571d5dfb2c94"},
+    {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a702e66483b1fe602717020a0e90506e759c84a71dbc1616dd55d29d86a9b91f"},
+    {file = "coverage-7.3.3-cp39-cp39-win32.whl", hash = "sha256:7fbf3f5756e7955174a31fb579307d69ffca91ad163467ed123858ce0f3fd4aa"},
+    {file = "coverage-7.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cad9afc1644b979211989ec3ff7d82110b2ed52995c2f7263e7841c846a75348"},
+    {file = "coverage-7.3.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:d299d379b676812e142fb57662a8d0d810b859421412b4d7af996154c00c31bb"},
+    {file = "coverage-7.3.3.tar.gz", hash = "sha256:df04c64e58df96b4427db8d0559e95e2df3138c9916c96f9f6a4dd220db2fdb7"},
 ]
 
 [package.extras]
@@ -435,68 +491,73 @@ toml = ["tomli"]
 
 [[package]]
 name = "cryptography"
-version = "36.0.2"
+version = "41.0.7"
 description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"},
-    {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86"},
-    {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2"},
-    {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb"},
-    {file = "cryptography-36.0.2-cp36-abi3-win32.whl", hash = "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"},
-    {file = "cryptography-36.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3"},
-    {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"},
+    {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"},
+    {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"},
+    {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"},
+    {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"},
+    {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"},
+    {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"},
+    {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"},
+    {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"},
+    {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"},
+    {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"},
+    {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"},
+    {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"},
+    {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"},
+    {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"},
+    {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"},
+    {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"},
+    {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"},
+    {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"},
+    {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"},
+    {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"},
+    {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"},
+    {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"},
+    {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"},
 ]
 
 [package.dependencies]
 cffi = ">=1.12"
 
 [package.extras]
-docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
+docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"]
 docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
-pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
-sdist = ["setuptools-rust (>=0.11.4)"]
+nox = ["nox"]
+pep8test = ["black", "check-sdist", "mypy", "ruff"]
+sdist = ["build"]
 ssh = ["bcrypt (>=3.1.5)"]
-test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"]
+test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"]
+test-randomorder = ["pytest-randomly"]
 
 [[package]]
 name = "dbt-core"
-version = "1.6.5"
+version = "1.7.4"
 description = "With dbt, data analysts and engineers can build analytics the way engineers build applications."
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "dbt-core-1.6.5.tar.gz", hash = "sha256:c820c82cab8f2e98cb688c6ff9440a687181130369af9111d6cf3d0e9460122d"},
-    {file = "dbt_core-1.6.5-py3-none-any.whl", hash = "sha256:6dc3c094a71e400adb1081417265513267248c354b82420db9ad195a72a2f910"},
+    {file = "dbt-core-1.7.4.tar.gz", hash = "sha256:769b95949210cb0d1eafdb7be48b01e59984650403f86510fdee65bd0f70f76d"},
+    {file = "dbt_core-1.7.4-py3-none-any.whl", hash = "sha256:50050ae44fe9bad63e1b639810ed3629822cdc7a2af0eff6e08461c94c4527c0"},
 ]
 
 [package.dependencies]
 agate = ">=1.7.0,<1.8.0"
 cffi = ">=1.9,<2.0.0"
-click = "<9"
+click = ">=8.0.2,<9"
 colorama = ">=0.3.9,<0.5"
-dbt-extractor = ">=0.4.1,<0.5.0"
-dbt-semantic-interfaces = ">=0.2.0,<0.3.0"
-hologram = ">=0.0.16,<0.1.0"
+dbt-extractor = ">=0.5.0,<0.6.0"
+dbt-semantic-interfaces = ">=0.4.2,<0.5.0"
 idna = ">=2.5,<4"
 isodate = ">=0.6,<0.7"
 Jinja2 = ">=3.1.2,<3.2.0"
+jsonschema = ">=3.0"
 logbook = ">=1.5,<1.6"
-mashumaro = {version = ">=3.8.1,<3.9.0", extras = ["msgpack"]}
+mashumaro = {version = ">=3.9,<4.0", extras = ["msgpack"]}
 minimal-snowplow-tracker = ">=0.0.2,<0.1.0"
 networkx = ">=2.3,<4"
 packaging = ">20.9"
@@ -511,60 +572,60 @@ urllib3 = ">=1.0,<2.0"
 
 [[package]]
 name = "dbt-extractor"
-version = "0.4.1"
+version = "0.5.1"
 description = "A tool to analyze and extract information from Jinja used in dbt projects."
 optional = false
 python-versions = ">=3.6.1"
 files = [
-    {file = "dbt_extractor-0.4.1-cp36-abi3-macosx_10_7_x86_64.whl", hash = "sha256:4dc715bd740e418d8dc1dd418fea508e79208a24cf5ab110b0092a3cbe96bf71"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:bc9e0050e3a2f4ea9fe58e8794bc808e6709a0c688ed710fc7c5b6ef3e5623ec"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76872cdee659075d6ce2df92dc62e59a74ba571be62acab2e297ca478b49d766"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81435841610be1b07806d72cd89b1956c6e2a84c360b9ceb3f949c62a546d569"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7c291f9f483eae4f60dd5859097d7ba51d5cb6c4725f08973ebd18cdea89d758"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:822b1e911db230e1b9701c99896578e711232001027b518c44c32f79a46fa3f9"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:554d27741a54599c39e5c0b7dbcab77400d83f908caba284a3e960db812e5814"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a805d51a25317f53cbff951c79b9cf75421cf48e4b3e1dfb3e9e8de6d824b76c"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cad90ddc708cb4182dc16fe2c87b1f088a1679877b93e641af068eb68a25d582"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:34783d788b133f223844e280e37b3f5244f2fb60acc457aa75c2667e418d5442"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:9da211869a1220ea55c5552c1567a3ea5233a6c52fa89ca87a22465481c37bc9"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:7d7c47774dc051b8c18690281a55e2e3d3320e823b17e04b06bc3ff81b1874ba"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:037907a7c7ae0391045d81338ca77ddaef899a91d80f09958f09fe374594e19b"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-win32.whl", hash = "sha256:3fe8d8e28a7bd3e0884896147269ca0202ca432d8733113386bdc84c824561bf"},
-    {file = "dbt_extractor-0.4.1-cp36-abi3-win_amd64.whl", hash = "sha256:35265a0ae0a250623b0c2e3308b2738dc8212e40e0aa88407849e9ea090bb312"},
-    {file = "dbt_extractor-0.4.1.tar.gz", hash = "sha256:75b1c665699ec0f1ffce1ba3d776f7dfce802156f22e70a7b9c8f0b4d7e80f42"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3b91e6106b967d908b34f83929d3f50ee2b498876a1be9c055fe060ed728c556"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3614ce9f83ae4cd0dc95f77730034a793a1c090a52dcf698ba1c94050afe3a8b"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ea4edf33035d0a060b1e01c42fb2d99316457d44c954d6ed4eed9f1948664d87"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3b9bf50eb062b4344d9546fe42038996c6e7e7daa10724aa955d64717260e5d"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c0ce901d4ebf0664977e4e1cbf596d4afc6c1339fcc7d2cf67ce3481566a626f"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cbe338b76e9ffaa18275456e041af56c21bb517f6fbda7a58308138703da0996"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b25fa7a276ab26aa2d70ff6e0cf4cfb1490d7831fb57ee1337c24d2b0333b84"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5651e458be910ff567c0da3ea2eb084fd01884cc88888ac2cf1e240dcddacc2"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62e4f040fd338b652683421ce48e903812e27fd6e7af58b1b70a4e1f9f2c79e3"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91e25ad78f1f4feadd27587ebbcc46ad909cfad843118908f30336d08d8400ca"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:cdf9938b36cd098bcdd80f43dc03864da3f69f57d903a9160a32236540d4ddcd"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:475e2c05b17eb4976eff6c8f7635be42bec33f15a74ceb87a40242c94a99cebf"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:100453ba06e169cbdb118234ab3f06f6722a2e0e316089b81c88dea701212abc"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-win32.whl", hash = "sha256:6916aae085fd5f2af069fd6947933e78b742c9e3d2165e1740c2e28ae543309a"},
+    {file = "dbt_extractor-0.5.1-cp38-abi3-win_amd64.whl", hash = "sha256:eecc08f3743e802a8ede60c89f7b2bce872acc86120cbc0ae7df229bb8a95083"},
+    {file = "dbt_extractor-0.5.1.tar.gz", hash = "sha256:cd5d95576a8dea4190240aaf9936a37fd74b4b7913ca69a3c368fc4472bb7e13"},
 ]
 
 [[package]]
 name = "dbt-semantic-interfaces"
-version = "0.2.0"
+version = "0.4.2"
 description = "The shared semantic layer definitions that dbt-core and MetricFlow use"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "dbt_semantic_interfaces-0.2.0-py3-none-any.whl", hash = "sha256:823c9bd53745604cae2af854c7d5064056383d0304560c35236a33c5f0e52090"},
-    {file = "dbt_semantic_interfaces-0.2.0.tar.gz", hash = "sha256:4afecc6dc56f85ecce7ac424dea07561513467e0bf28ead7307b78a22e6b999b"},
+    {file = "dbt_semantic_interfaces-0.4.2-py3-none-any.whl", hash = "sha256:feee60eed3b4601ca92f541ed9337c6c1077cf97b10374848d7f4f6d33c358e2"},
+    {file = "dbt_semantic_interfaces-0.4.2.tar.gz", hash = "sha256:7b222719cb57e77b2570033cd258b8e3e1ed575cdc1864ff74be97ba9c3394b9"},
 ]
 
 [package.dependencies]
 click = ">=7.0,<9.0"
 importlib-metadata = ">=6.0,<7.0"
 jinja2 = ">=3.0,<4.0"
-jsonschema = ">=3.0,<4.0"
-more-itertools = ">=8.0,<9.0"
+jsonschema = ">=4.0,<5.0"
+more-itertools = ">=8.0,<11.0"
 pydantic = ">=1.10,<2.0"
 python-dateutil = ">=2.0,<3.0"
 pyyaml = ">=6.0,<7.0"
-typing-extensions = ">=4.0,<5.0"
+typing-extensions = ">=4.4,<5.0"
 
 [[package]]
 name = "distlib"
-version = "0.3.7"
+version = "0.3.8"
 description = "Distribution utilities"
 optional = false
 python-versions = "*"
 files = [
-    {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"},
-    {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"},
+    {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
+    {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
 ]
 
 [[package]]
@@ -579,109 +640,77 @@ files = [
 
 [[package]]
 name = "duckdb"
-version = "0.7.1"
+version = "0.9.2"
 description = "DuckDB embedded database"
 optional = false
-python-versions = "*"
-files = [
-    {file = "duckdb-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3e0170be6cc315c179169dfa3e06485ef7009ef8ce399cd2908f29105ef2c67b"},
-    {file = "duckdb-0.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6360d41023e726646507d5479ba60960989a09f04527b36abeef3643c61d8c48"},
-    {file = "duckdb-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:578c269d7aa27184e8d45421694f89deda3f41fe6bd2a8ce48b262b9fc975326"},
-    {file = "duckdb-0.7.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36aae9a923c9f78da1cf3fcf75873f62d32ea017d4cef7c706d16d3eca527ca2"},
-    {file = "duckdb-0.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:630e0122a02f19bb1fafae00786350b2c31ae8422fce97c827bd3686e7c386af"},
-    {file = "duckdb-0.7.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9b9ca2d294725e523ce207bc37f28787478ae6f7a223e2cf3a213a2d498596c3"},
-    {file = "duckdb-0.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0bd89f388205b6c99b62650169efe9a02933555ee1d46ddf79fbd0fb9e62652b"},
-    {file = "duckdb-0.7.1-cp310-cp310-win32.whl", hash = "sha256:a9e987565a268fd8da9f65e54621d28f39c13105b8aee34c96643074babe6d9c"},
-    {file = "duckdb-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:5d986b5ad1307b069309f9707c0c5051323e29865aefa059eb6c3b22dc9751b6"},
-    {file = "duckdb-0.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:54606dfd24d7181d3098030ca6858f6be52f3ccbf42fff05f7587f2d9cdf4343"},
-    {file = "duckdb-0.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd9367ae650b6605ffe00412183cf0edb688a5fc9fbb03ed757e8310e7ec3b6c"},
-    {file = "duckdb-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aaf33aeb543c7816bd915cd10141866d54f92f698e1b5712de9d8b7076da19df"},
-    {file = "duckdb-0.7.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e56b0329c38c0356b40449917bab6fce6ac27d356257b9a9da613d2a0f064e0"},
-    {file = "duckdb-0.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:604b8b476d6cc6bf91625d8c2722ef9c50c402b3d64bc518c838d6c279e6d93b"},
-    {file = "duckdb-0.7.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:32a268508c6d7fdc99d5442736051de74c28a5166c4cc3dcbbf35d383299b941"},
-    {file = "duckdb-0.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90794406fa2111414877ee9db154fef940911f3920c312c1cf69947621737c8d"},
-    {file = "duckdb-0.7.1-cp311-cp311-win32.whl", hash = "sha256:bf20c5ee62cbbf10b39ebdfd70d454ce914e70545c7cb6cb78cb5befef96328a"},
-    {file = "duckdb-0.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bb2700785cab37cd1e7a76c4547a5ab0f8a7c28ad3f3e4d02a8fae52be223090"},
-    {file = "duckdb-0.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b09741cfa31388b8f9cdf5c5200e0995d55a5b54d2d1a75b54784e2f5c042f7f"},
-    {file = "duckdb-0.7.1-cp36-cp36m-win32.whl", hash = "sha256:766e6390f7ace7f1e322085c2ca5d0ad94767bde78a38d168253d2b0b4d5cd5c"},
-    {file = "duckdb-0.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6a3f3315e2b553db3463f07324f62dfebaf3b97656a87558e59e2f1f816eaf15"},
-    {file = "duckdb-0.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:278edb8c912d836b3b77fd1695887e1dbd736137c3912478af3608c9d7307bb0"},
-    {file = "duckdb-0.7.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e189b558d10b58fe6ed85ce79f728e143eb4115db1e63147a44db613cd4dd0d9"},
-    {file = "duckdb-0.7.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b91ec3544ee4dc9e6abbdf2669475d5adedaaea51987c67acf161673e6b7443"},
-    {file = "duckdb-0.7.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fe3f3dbd62b76a773144eef31aa29794578c359da932e77fef04516535318ca"},
-    {file = "duckdb-0.7.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1e78c7f59325e99f0b3d9fe7c2bad4aaadf42d2c7711925cc26331d7647a91b2"},
-    {file = "duckdb-0.7.1-cp37-cp37m-win32.whl", hash = "sha256:bc2a12d9f4fc8ef2fd1022d610287c9fc9972ea06b7510fc87387f1fa256a390"},
-    {file = "duckdb-0.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:53e3db1bc0f445ee48b23cde47bfba08c7fa5a69976c740ec8cdf89543d2405d"},
-    {file = "duckdb-0.7.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1247cc11bac17f2585d11681329806c86295e32242f84a10a604665e697d5c81"},
-    {file = "duckdb-0.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5feaff16a012075b49dfa09d4cb24455938d6b0e06b08e1404ec00089119dba2"},
-    {file = "duckdb-0.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b411a0c361eab9b26dcd0d0c7a0d1bc0ad6b214068555de7e946fbdd2619961a"},
-    {file = "duckdb-0.7.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c76d8694ecdb579241ecfeaf03c51d640b984dbbe8e1d9f919089ebf3cdea6"},
-    {file = "duckdb-0.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193b896eed44d8751a755ccf002a137630020af0bc3505affa21bf19fdc90df3"},
-    {file = "duckdb-0.7.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7da132ee452c80a3784b8daffd86429fa698e1b0e3ecb84660db96d36c27ad55"},
-    {file = "duckdb-0.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5fd08c97c3e8cb5bec3822cf78b966b489213dcaab24b25c05a99f7caf8db467"},
-    {file = "duckdb-0.7.1-cp38-cp38-win32.whl", hash = "sha256:9cb956f94fa55c4782352dac7cc7572a58312bd7ce97332bb14591d6059f0ea4"},
-    {file = "duckdb-0.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:289a5f65213e66d320ebcd51a94787e7097b9d1c3492d01a121a2c809812bf19"},
-    {file = "duckdb-0.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8085ad58c9b5854ee3820804fa1797e6b3134429c1506c3faab3cb96e71b07e9"},
-    {file = "duckdb-0.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b47c19d1f2f662a5951fc6c5f6939d0d3b96689604b529cdcffd9afdcc95bff2"},
-    {file = "duckdb-0.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6a611f598226fd634b7190f509cc6dd668132ffe436b0a6b43847b4b32b99e4a"},
-    {file = "duckdb-0.7.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6730f03b5b78f3943b752c90bdf37b62ae3ac52302282a942cc675825b4a8dc9"},
-    {file = "duckdb-0.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe23e938d29cd8ea6953d77dc828b7f5b95a4dbc7cd7fe5bcc3531da8cec3dba"},
-    {file = "duckdb-0.7.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:feffe503c2e2a99480e1e5e15176f37796b3675e4dadad446fe7c2cc672aed3c"},
-    {file = "duckdb-0.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72fceb06f5bf24ad6bb5974c60d397a7a7e61b3d847507a22276de076f3392e2"},
-    {file = "duckdb-0.7.1-cp39-cp39-win32.whl", hash = "sha256:c4d5217437d20d05fe23317bbc161befa1f9363f3622887cd1d2f4719b407936"},
-    {file = "duckdb-0.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:066885e1883464ce3b7d1fd844f9431227dcffe1ee39bfd2a05cd6d53f304557"},
-    {file = "duckdb-0.7.1.tar.gz", hash = "sha256:a7db6da0366b239ea1e4541fcc19556b286872f5015c9a54c2e347146e25a2ad"},
+python-versions = ">=3.7.0"
+files = [
+    {file = "duckdb-0.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aadcea5160c586704c03a8a796c06a8afffbefefb1986601104a60cb0bfdb5ab"},
+    {file = "duckdb-0.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:08215f17147ed83cbec972175d9882387366de2ed36c21cbe4add04b39a5bcb4"},
+    {file = "duckdb-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6c2a8aba6850abef5e1be9dbc04b8e72a5b2c2b67f77892317a21fae868fe7"},
+    {file = "duckdb-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ff49f3da9399900fd58b5acd0bb8bfad22c5147584ad2427a78d937e11ec9d0"},
+    {file = "duckdb-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5ac5baf8597efd2bfa75f984654afcabcd698342d59b0e265a0bc6f267b3f0"},
+    {file = "duckdb-0.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:81c6df905589a1023a27e9712edb5b724566587ef280a0c66a7ec07c8083623b"},
+    {file = "duckdb-0.9.2-cp310-cp310-win32.whl", hash = "sha256:a298cd1d821c81d0dec8a60878c4b38c1adea04a9675fb6306c8f9083bbf314d"},
+    {file = "duckdb-0.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:492a69cd60b6cb4f671b51893884cdc5efc4c3b2eb76057a007d2a2295427173"},
+    {file = "duckdb-0.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:061a9ea809811d6e3025c5de31bc40e0302cfb08c08feefa574a6491e882e7e8"},
+    {file = "duckdb-0.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a43f93be768af39f604b7b9b48891f9177c9282a408051209101ff80f7450d8f"},
+    {file = "duckdb-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac29c8c8f56fff5a681f7bf61711ccb9325c5329e64f23cb7ff31781d7b50773"},
+    {file = "duckdb-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b14d98d26bab139114f62ade81350a5342f60a168d94b27ed2c706838f949eda"},
+    {file = "duckdb-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:796a995299878913e765b28cc2b14c8e44fae2f54ab41a9ee668c18449f5f833"},
+    {file = "duckdb-0.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6cb64ccfb72c11ec9c41b3cb6181b6fd33deccceda530e94e1c362af5f810ba1"},
+    {file = "duckdb-0.9.2-cp311-cp311-win32.whl", hash = "sha256:930740cb7b2cd9e79946e1d3a8f66e15dc5849d4eaeff75c8788d0983b9256a5"},
+    {file = "duckdb-0.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:c28f13c45006fd525001b2011cdf91fa216530e9751779651e66edc0e446be50"},
+    {file = "duckdb-0.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fbce7bbcb4ba7d99fcec84cec08db40bc0dd9342c6c11930ce708817741faeeb"},
+    {file = "duckdb-0.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15a82109a9e69b1891f0999749f9e3265f550032470f51432f944a37cfdc908b"},
+    {file = "duckdb-0.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9490fb9a35eb74af40db5569d90df8a04a6f09ed9a8c9caa024998c40e2506aa"},
+    {file = "duckdb-0.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:696d5c6dee86c1a491ea15b74aafe34ad2b62dcd46ad7e03b1d00111ca1a8c68"},
+    {file = "duckdb-0.9.2-cp37-cp37m-win32.whl", hash = "sha256:4f0935300bdf8b7631ddfc838f36a858c1323696d8c8a2cecbd416bddf6b0631"},
+    {file = "duckdb-0.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:0aab900f7510e4d2613263865570203ddfa2631858c7eb8cbed091af6ceb597f"},
+    {file = "duckdb-0.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d8130ed6a0c9421b135d0743705ea95b9a745852977717504e45722c112bf7a"},
+    {file = "duckdb-0.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:974e5de0294f88a1a837378f1f83330395801e9246f4e88ed3bfc8ada65dcbee"},
+    {file = "duckdb-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4fbc297b602ef17e579bb3190c94d19c5002422b55814421a0fc11299c0c1100"},
+    {file = "duckdb-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dd58a0d84a424924a35b3772419f8cd78a01c626be3147e4934d7a035a8ad68"},
+    {file = "duckdb-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11a1194a582c80dfb57565daa06141727e415ff5d17e022dc5f31888a5423d33"},
+    {file = "duckdb-0.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:be45d08541002a9338e568dca67ab4f20c0277f8f58a73dfc1435c5b4297c996"},
+    {file = "duckdb-0.9.2-cp38-cp38-win32.whl", hash = "sha256:dd6f88aeb7fc0bfecaca633629ff5c986ac966fe3b7dcec0b2c48632fd550ba2"},
+    {file = "duckdb-0.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:28100c4a6a04e69aa0f4a6670a6d3d67a65f0337246a0c1a429f3f28f3c40b9a"},
+    {file = "duckdb-0.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ae5bf0b6ad4278e46e933e51473b86b4b932dbc54ff097610e5b482dd125552"},
+    {file = "duckdb-0.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e5d0bb845a80aa48ed1fd1d2d285dd352e96dc97f8efced2a7429437ccd1fe1f"},
+    {file = "duckdb-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ce262d74a52500d10888110dfd6715989926ec936918c232dcbaddb78fc55b4"},
+    {file = "duckdb-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6935240da090a7f7d2666f6d0a5e45ff85715244171ca4e6576060a7f4a1200e"},
+    {file = "duckdb-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5cfb93e73911696a98b9479299d19cfbc21dd05bb7ab11a923a903f86b4d06e"},
+    {file = "duckdb-0.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:64e3bc01751f31e7572d2716c3e8da8fe785f1cdc5be329100818d223002213f"},
+    {file = "duckdb-0.9.2-cp39-cp39-win32.whl", hash = "sha256:6e5b80f46487636368e31b61461940e3999986359a78660a50dfdd17dd72017c"},
+    {file = "duckdb-0.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:e6142a220180dbeea4f341708bd5f9501c5c962ce7ef47c1cadf5e8810b4cb13"},
+    {file = "duckdb-0.9.2.tar.gz", hash = "sha256:3843afeab7c3fc4a4c0b53686a4cc1d9cdbdadcbb468d60fef910355ecafd447"},
 ]
 
 [[package]]
 name = "filelock"
-version = "3.12.2"
+version = "3.13.1"
 description = "A platform independent file lock."
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
-    {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
+    {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
+    {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
 ]
 
 [package.extras]
-docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
-testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"]
-
-[[package]]
-name = "future"
-version = "0.18.3"
-description = "Clean single-source support for Python 3 and 2"
-optional = false
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-files = [
-    {file = "future-0.18.3.tar.gz", hash = "sha256:34a17436ed1e96697a86f9de3d15a3b0be01d8bc8de9c1dffd59fb8234ed5307"},
-]
-
-[[package]]
-name = "hologram"
-version = "0.0.16"
-description = "JSON schema generation from dataclasses"
-optional = false
-python-versions = "*"
-files = [
-    {file = "hologram-0.0.16-py3-none-any.whl", hash = "sha256:4e56bd525336bb64a18916f871977a4125b64be8aaa750233583003333cda361"},
-    {file = "hologram-0.0.16.tar.gz", hash = "sha256:1c2c921b4e575361623ea0e0d0aa5aee377b1a333cc6c6a879e213ed34583e55"},
-]
-
-[package.dependencies]
-jsonschema = ">=3.0"
-python-dateutil = ">=2.8,<2.9"
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+typing = ["typing-extensions (>=4.8)"]
 
 [[package]]
 name = "identify"
-version = "2.5.31"
+version = "2.5.33"
 description = "File identification library for Python"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"},
-    {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"},
+    {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"},
+    {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"},
 ]
 
 [package.extras]
@@ -689,51 +718,51 @@ license = ["ukkonen"]
 
 [[package]]
 name = "idna"
-version = "3.4"
+version = "3.6"
 description = "Internationalized Domain Names in Applications (IDNA)"
 optional = false
 python-versions = ">=3.5"
 files = [
-    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
-    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+    {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"},
+    {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"},
 ]
 
 [[package]]
 name = "importlib-metadata"
-version = "6.8.0"
+version = "6.11.0"
 description = "Read metadata from Python packages"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
-    {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"},
+    {file = "importlib_metadata-6.11.0-py3-none-any.whl", hash = "sha256:f0afba6205ad8f8947c7d338b5342d5db2afbfd82f9cbef7879a9539cc12eb9b"},
+    {file = "importlib_metadata-6.11.0.tar.gz", hash = "sha256:1231cf92d825c9e03cfc4da076a16de6422c863558229ea0b22b675657463443"},
 ]
 
 [package.dependencies]
 zipp = ">=0.5"
 
 [package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
 perf = ["ipython"]
 testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"]
 
 [[package]]
 name = "importlib-resources"
-version = "5.12.0"
+version = "6.1.1"
 description = "Read resources from Python packages"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"},
-    {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"},
+    {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"},
+    {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"},
 ]
 
 [package.dependencies]
 zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""}
 
 [package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"]
 
 [[package]]
 name = "isodate"
@@ -751,21 +780,21 @@ six = "*"
 
 [[package]]
 name = "jaraco-classes"
-version = "3.2.3"
+version = "3.3.0"
 description = "Utility functions for Python class constructs"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "jaraco.classes-3.2.3-py3-none-any.whl", hash = "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158"},
-    {file = "jaraco.classes-3.2.3.tar.gz", hash = "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"},
+    {file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"},
+    {file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"},
 ]
 
 [package.dependencies]
 more-itertools = "*"
 
 [package.extras]
-docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
 
 [[package]]
 name = "jeepney"
@@ -801,34 +830,51 @@ i18n = ["Babel (>=2.7)"]
 
 [[package]]
 name = "jsonschema"
-version = "3.1.1"
+version = "4.20.0"
 description = "An implementation of JSON Schema validation for Python"
 optional = false
-python-versions = "*"
+python-versions = ">=3.8"
 files = [
-    {file = "jsonschema-3.1.1-py2.py3-none-any.whl", hash = "sha256:94c0a13b4a0616458b42529091624e66700a17f847453e52279e35509a5b7631"},
-    {file = "jsonschema-3.1.1.tar.gz", hash = "sha256:2fa0684276b6333ff3c0b1b27081f4b2305f0a36cf702a23db50edb141893c3f"},
+    {file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"},
+    {file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"},
 ]
 
 [package.dependencies]
-attrs = ">=17.4.0"
-importlib-metadata = "*"
-pyrsistent = ">=0.14.0"
-setuptools = "*"
-six = ">=1.11.0"
+attrs = ">=22.2.0"
+importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
+jsonschema-specifications = ">=2023.03.6"
+pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""}
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
 
 [package.extras]
-format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2023.11.2"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "jsonschema_specifications-2023.11.2-py3-none-any.whl", hash = "sha256:e74ba7c0a65e8cb49dc26837d6cfe576557084a8b423ed16a420984228104f93"},
+    {file = "jsonschema_specifications-2023.11.2.tar.gz", hash = "sha256:9472fc4fea474cd74bea4a2b190daeccb5a9e4db2ea80efcf7a1b582fc9a81b8"},
+]
+
+[package.dependencies]
+importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""}
+referencing = ">=0.31.0"
 
 [[package]]
 name = "keyring"
-version = "23.13.1"
+version = "24.3.0"
 description = "Store and access your passwords safely."
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "keyring-23.13.1-py3-none-any.whl", hash = "sha256:771ed2a91909389ed6148631de678f82ddc73737d85a927f382a8a1b157898cd"},
-    {file = "keyring-23.13.1.tar.gz", hash = "sha256:ba2e15a9b35e21908d0aaf4e0a47acc52d6ae33444df0da2b49d41a46ef6d678"},
+    {file = "keyring-24.3.0-py3-none-any.whl", hash = "sha256:4446d35d636e6a10b8bce7caa66913dd9eca5fd222ca03a3d42c38608ac30836"},
+    {file = "keyring-24.3.0.tar.gz", hash = "sha256:e730ecffd309658a08ee82535a3b5ec4b4c8669a9be11efb66249d8e0aeb9a25"},
 ]
 
 [package.dependencies]
@@ -840,9 +886,9 @@ pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""}
 SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""}
 
 [package.extras]
-completion = ["shtab"]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+completion = ["shtab (>=1.1.0)"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
 
 [[package]]
 name = "lark-parser"
@@ -902,93 +948,98 @@ sqlalchemy = ["sqlalchemy"]
 test = ["mock", "pytest", "pytest-cov (<2.6)"]
 zmq = ["pyzmq"]
 
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+    {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark"]
+code-style = ["pre-commit (>=3.0,<4.0)"]
+compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
+linkify = ["linkify-it-py (>=1,<3)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
 [[package]]
 name = "markupsafe"
-version = "2.0.1"
+version = "2.1.3"
 description = "Safely add untrusted strings to HTML/XML markup."
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"},
-    {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"},
-    {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"},
-    {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"},
-    {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"},
-    {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"},
-    {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
+    {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
+    {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
+    {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
+    {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
+    {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
+    {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
 ]
 
 [[package]]
 name = "mashumaro"
-version = "3.8.1"
+version = "3.10"
 description = "Fast serialization library on top of dataclasses"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "mashumaro-3.8.1-py3-none-any.whl", hash = "sha256:e060469a4bec1c86f8145ea27ecd99027ea3e343075a4efcb5e8a969a45b9fb9"},
-    {file = "mashumaro-3.8.1.tar.gz", hash = "sha256:8bae8b25e2287b75094655b8ba8635f34016c09ca16498188f2f3b198d88b7ef"},
+    {file = "mashumaro-3.10-py3-none-any.whl", hash = "sha256:d2c0fd5e7878987629d41f4986d9b0903d362a92eeb299b7d88b87eb113f4f48"},
+    {file = "mashumaro-3.10.tar.gz", hash = "sha256:0248a5c8574aa6cd20696621502d38a7ea66af3d6d93c5d03f93b33298edc878"},
 ]
 
 [package.dependencies]
@@ -1001,6 +1052,17 @@ orjson = ["orjson"]
 toml = ["tomli (>=1.1.0)", "tomli-w (>=1.0)"]
 yaml = ["pyyaml (>=3.13)"]
 
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+    {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
 [[package]]
 name = "minimal-snowplow-tracker"
 version = "0.0.2"
@@ -1017,74 +1079,78 @@ six = ">=1.9.0,<2.0"
 
 [[package]]
 name = "more-itertools"
-version = "8.14.0"
+version = "10.1.0"
 description = "More routines for operating on iterables, beyond itertools"
 optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.8"
 files = [
-    {file = "more-itertools-8.14.0.tar.gz", hash = "sha256:c09443cd3d5438b8dafccd867a6bc1cb0894389e90cb53d227456b0b0bccb750"},
-    {file = "more_itertools-8.14.0-py3-none-any.whl", hash = "sha256:1bc4f91ee5b1b31ac7ceacc17c09befe6a40a503907baf9c839c229b5095cfd2"},
+    {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"},
+    {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"},
 ]
 
 [[package]]
 name = "msgpack"
-version = "1.0.4"
+version = "1.0.7"
 description = "MessagePack serializer"
 optional = false
-python-versions = "*"
+python-versions = ">=3.8"
 files = [
-    {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"},
-    {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"},
-    {file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"},
-    {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"},
-    {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"},
-    {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"},
-    {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"},
-    {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"},
-    {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"},
-    {file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"},
-    {file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"},
-    {file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"},
-    {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"},
-    {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"},
-    {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"},
-    {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"},
-    {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"},
-    {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"},
-    {file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"},
-    {file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"},
-    {file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"},
-    {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"},
-    {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"},
-    {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"},
-    {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"},
-    {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"},
-    {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"},
-    {file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"},
-    {file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"},
-    {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"},
-    {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"},
-    {file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"},
-    {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"},
-    {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"},
-    {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"},
-    {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"},
-    {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"},
-    {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"},
-    {file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"},
-    {file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"},
-    {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"},
-    {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"},
-    {file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"},
-    {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"},
-    {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"},
-    {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"},
-    {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"},
-    {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"},
-    {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"},
-    {file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"},
-    {file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"},
-    {file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"},
+    {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04ad6069c86e531682f9e1e71b71c1c3937d6014a7c3e9edd2aa81ad58842862"},
+    {file = "msgpack-1.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cca1b62fe70d761a282496b96a5e51c44c213e410a964bdffe0928e611368329"},
+    {file = "msgpack-1.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e50ebce52f41370707f1e21a59514e3375e3edd6e1832f5e5235237db933c98b"},
+    {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7b4f35de6a304b5533c238bee86b670b75b03d31b7797929caa7a624b5dda6"},
+    {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28efb066cde83c479dfe5a48141a53bc7e5f13f785b92ddde336c716663039ee"},
+    {file = "msgpack-1.0.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4cb14ce54d9b857be9591ac364cb08dc2d6a5c4318c1182cb1d02274029d590d"},
+    {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b573a43ef7c368ba4ea06050a957c2a7550f729c31f11dd616d2ac4aba99888d"},
+    {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ccf9a39706b604d884d2cb1e27fe973bc55f2890c52f38df742bc1d79ab9f5e1"},
+    {file = "msgpack-1.0.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cb70766519500281815dfd7a87d3a178acf7ce95390544b8c90587d76b227681"},
+    {file = "msgpack-1.0.7-cp310-cp310-win32.whl", hash = "sha256:b610ff0f24e9f11c9ae653c67ff8cc03c075131401b3e5ef4b82570d1728f8a9"},
+    {file = "msgpack-1.0.7-cp310-cp310-win_amd64.whl", hash = "sha256:a40821a89dc373d6427e2b44b572efc36a2778d3f543299e2f24eb1a5de65415"},
+    {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:576eb384292b139821c41995523654ad82d1916da6a60cff129c715a6223ea84"},
+    {file = "msgpack-1.0.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:730076207cb816138cf1af7f7237b208340a2c5e749707457d70705715c93b93"},
+    {file = "msgpack-1.0.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:85765fdf4b27eb5086f05ac0491090fc76f4f2b28e09d9350c31aac25a5aaff8"},
+    {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3476fae43db72bd11f29a5147ae2f3cb22e2f1a91d575ef130d2bf49afd21c46"},
+    {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d4c80667de2e36970ebf74f42d1088cc9ee7ef5f4e8c35eee1b40eafd33ca5b"},
+    {file = "msgpack-1.0.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b0bf0effb196ed76b7ad883848143427a73c355ae8e569fa538365064188b8e"},
+    {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f9a7c509542db4eceed3dcf21ee5267ab565a83555c9b88a8109dcecc4709002"},
+    {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84b0daf226913133f899ea9b30618722d45feffa67e4fe867b0b5ae83a34060c"},
+    {file = "msgpack-1.0.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ec79ff6159dffcc30853b2ad612ed572af86c92b5168aa3fc01a67b0fa40665e"},
+    {file = "msgpack-1.0.7-cp311-cp311-win32.whl", hash = "sha256:3e7bf4442b310ff154b7bb9d81eb2c016b7d597e364f97d72b1acc3817a0fdc1"},
+    {file = "msgpack-1.0.7-cp311-cp311-win_amd64.whl", hash = "sha256:3f0c8c6dfa6605ab8ff0611995ee30d4f9fcff89966cf562733b4008a3d60d82"},
+    {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f0936e08e0003f66bfd97e74ee530427707297b0d0361247e9b4f59ab78ddc8b"},
+    {file = "msgpack-1.0.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98bbd754a422a0b123c66a4c341de0474cad4a5c10c164ceed6ea090f3563db4"},
+    {file = "msgpack-1.0.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b291f0ee7961a597cbbcc77709374087fa2a9afe7bdb6a40dbbd9b127e79afee"},
+    {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebbbba226f0a108a7366bf4b59bf0f30a12fd5e75100c630267d94d7f0ad20e5"},
+    {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e2d69948e4132813b8d1131f29f9101bc2c915f26089a6d632001a5c1349672"},
+    {file = "msgpack-1.0.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdf38ba2d393c7911ae989c3bbba510ebbcdf4ecbdbfec36272abe350c454075"},
+    {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:993584fc821c58d5993521bfdcd31a4adf025c7d745bbd4d12ccfecf695af5ba"},
+    {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:52700dc63a4676669b341ba33520f4d6e43d3ca58d422e22ba66d1736b0a6e4c"},
+    {file = "msgpack-1.0.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e45ae4927759289c30ccba8d9fdce62bb414977ba158286b5ddaf8df2cddb5c5"},
+    {file = "msgpack-1.0.7-cp312-cp312-win32.whl", hash = "sha256:27dcd6f46a21c18fa5e5deed92a43d4554e3df8d8ca5a47bf0615d6a5f39dbc9"},
+    {file = "msgpack-1.0.7-cp312-cp312-win_amd64.whl", hash = "sha256:7687e22a31e976a0e7fc99c2f4d11ca45eff652a81eb8c8085e9609298916dcf"},
+    {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5b6ccc0c85916998d788b295765ea0e9cb9aac7e4a8ed71d12e7d8ac31c23c95"},
+    {file = "msgpack-1.0.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:235a31ec7db685f5c82233bddf9858748b89b8119bf4538d514536c485c15fe0"},
+    {file = "msgpack-1.0.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cab3db8bab4b7e635c1c97270d7a4b2a90c070b33cbc00c99ef3f9be03d3e1f7"},
+    {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bfdd914e55e0d2c9e1526de210f6fe8ffe9705f2b1dfcc4aecc92a4cb4b533d"},
+    {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e17c4592231a7dbd2ed09027823ab295d2791b3b1efb2aee874b10548b7524"},
+    {file = "msgpack-1.0.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38949d30b11ae5f95c3c91917ee7a6b239f5ec276f271f28638dec9156f82cfc"},
+    {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ff1d0899f104f3921d94579a5638847f783c9b04f2d5f229392ca77fba5b82fc"},
+    {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc43f1ec66eb8440567186ae2f8c447d91e0372d793dfe8c222aec857b81a8cf"},
+    {file = "msgpack-1.0.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dd632777ff3beaaf629f1ab4396caf7ba0bdd075d948a69460d13d44357aca4c"},
+    {file = "msgpack-1.0.7-cp38-cp38-win32.whl", hash = "sha256:4e71bc4416de195d6e9b4ee93ad3f2f6b2ce11d042b4d7a7ee00bbe0358bd0c2"},
+    {file = "msgpack-1.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:8f5b234f567cf76ee489502ceb7165c2a5cecec081db2b37e35332b537f8157c"},
+    {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfef2bb6ef068827bbd021017a107194956918ab43ce4d6dc945ffa13efbc25f"},
+    {file = "msgpack-1.0.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:484ae3240666ad34cfa31eea7b8c6cd2f1fdaae21d73ce2974211df099a95d81"},
+    {file = "msgpack-1.0.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3967e4ad1aa9da62fd53e346ed17d7b2e922cba5ab93bdd46febcac39be636fc"},
+    {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd178c4c80706546702c59529ffc005681bd6dc2ea234c450661b205445a34d"},
+    {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6ffbc252eb0d229aeb2f9ad051200668fc3a9aaa8994e49f0cb2ffe2b7867e7"},
+    {file = "msgpack-1.0.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ea70dc4018c7e6223f13affd1c5c30c0f5c12ac1f96cd8e9949acddb48a61"},
+    {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:384d779f0d6f1b110eae74cb0659d9aa6ff35aaf547b3955abf2ab4c901c4819"},
+    {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f64e376cd20d3f030190e8c32e1c64582eba56ac6dc7d5b0b49a9d44021b52fd"},
+    {file = "msgpack-1.0.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ed82f5a7af3697b1c4786053736f24a0efd0a1b8a130d4c7bfee4b9ded0f08f"},
+    {file = "msgpack-1.0.7-cp39-cp39-win32.whl", hash = "sha256:f26a07a6e877c76a88e3cecac8531908d980d3d5067ff69213653649ec0f60ad"},
+    {file = "msgpack-1.0.7-cp39-cp39-win_amd64.whl", hash = "sha256:1dc93e8e4653bdb5910aed79f11e165c85732067614f180f70534f056da97db3"},
+    {file = "msgpack-1.0.7.tar.gz", hash = "sha256:572efc93db7a4d27e404501975ca6d2d9775705c2d922390d878fcf768d92c87"},
 ]
 
 [[package]]
@@ -1124,21 +1190,21 @@ gssapi = ["gssapi (>=1.6.9)"]
 
 [[package]]
 name = "networkx"
-version = "2.6.3"
+version = "3.1"
 description = "Python package for creating and manipulating graphs and networks"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "networkx-2.6.3-py3-none-any.whl", hash = "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef"},
-    {file = "networkx-2.6.3.tar.gz", hash = "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51"},
+    {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"},
+    {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"},
 ]
 
 [package.extras]
-default = ["matplotlib (>=3.3)", "numpy (>=1.19)", "pandas (>=1.1)", "scipy (>=1.5,!=1.6.1)"]
-developer = ["black (==21.5b1)", "pre-commit (>=2.12)"]
-doc = ["nb2plots (>=0.6)", "numpydoc (>=1.1)", "pillow (>=8.2)", "pydata-sphinx-theme (>=0.6,<1.0)", "sphinx (>=4.0,<5.0)", "sphinx-gallery (>=0.9,<1.0)", "texext (>=0.6.6)"]
-extra = ["lxml (>=4.5)", "pydot (>=1.4.1)", "pygraphviz (>=1.7)"]
-test = ["codecov (>=2.1)", "pytest (>=6.2)", "pytest-cov (>=2.12)"]
+default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"]
+developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"]
+doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"]
+extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"]
+test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"]
 
 [[package]]
 name = "nodeenv"
@@ -1156,81 +1222,69 @@ setuptools = "*"
 
 [[package]]
 name = "oracledb"
-version = "1.3.2"
+version = "1.4.2"
 description = "Python interface to Oracle Database"
 optional = true
 python-versions = ">=3.6"
 files = [
-    {file = "oracledb-1.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:bee717f90118a95f0c661d27e7a65255eb5e400b95cbe4019b75014b3691ef90"},
-    {file = "oracledb-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000c5a31ecc5569e6dec4dcaf4552509d88a19051e57deb0af96296f9937dc6a"},
-    {file = "oracledb-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37c249c4323b61c3e333c2cf724e19e6416d35130acf0f684eefad17a73b040"},
-    {file = "oracledb-1.3.2-cp310-cp310-win32.whl", hash = "sha256:2680f460708904a2d2e4f853990bce10a963905205acf0e709c32cad353a5d2f"},
-    {file = "oracledb-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:0fdfa5e119270332eab1ee5900a503423e87d1b8ae6da17c426dd34822217213"},
-    {file = "oracledb-1.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de0ada0cbea8b1524f0798cedc38dabc9a8bfcb67f738b914e7a8eb873cc854a"},
-    {file = "oracledb-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:138904100c5218c33005ec5b07688ce68f40ea20c28b3b840738401ae2a862a1"},
-    {file = "oracledb-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:839f7a4d8d34130dd99a44c064bc9eea130a0d2406f723398ebb0b29b6d3a8cf"},
-    {file = "oracledb-1.3.2-cp311-cp311-win32.whl", hash = "sha256:8e37e2b41900a113894049f3c9d7b64e93f613ed52104f2f05ef3284e2e1bb8f"},
-    {file = "oracledb-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:cedd48e7d107884d4a19c9ad449b3c3cb3b3e4d67a6eddacb966b1370cc1f35e"},
-    {file = "oracledb-1.3.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a285f35edf435a7f60f54074d9925deb63146b4cc0f6998eba75a282c8ce497"},
-    {file = "oracledb-1.3.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e86e5203767e1216ceeda6b7c087b804fa2f44041680d5099900c3cf5724915"},
-    {file = "oracledb-1.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:043d7d5fdda0ea43734cd4cf67771efddc9307eef10cc83afc19599d39a23d72"},
-    {file = "oracledb-1.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08cff689d8117c817458a633859a35c21fc44f39bf56c9c8f62ec02789d0e1e0"},
-    {file = "oracledb-1.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2279f8550d80ed30315ef84e88b8ec5b533064e8a81ef96265647019ccee8e85"},
-    {file = "oracledb-1.3.2-cp37-cp37m-win32.whl", hash = "sha256:af8d8635453961556b84e37a1dd40c94e18d1b5d3b54020fafce0f3e67472b90"},
-    {file = "oracledb-1.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6e8710cdb14c4510f65c11c02f1d97c079d20e0692a431a1af0e964064b7e32c"},
-    {file = "oracledb-1.3.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9808e4169e3f330f2ea6dd15376432886d7ed84344f447048d9305a520f31a7a"},
-    {file = "oracledb-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0b760c58f73a262af01e093fc9b183de59516b618319fb53b281eedde1dccbc"},
-    {file = "oracledb-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ea5a26481c798978210505a1252eec6814cf28005e18a80f935cbcf5b74dabb"},
-    {file = "oracledb-1.3.2-cp38-cp38-win32.whl", hash = "sha256:790798eb1e9b96639c02e91f3b3f00934d722d9de0ac375adcda37b83bba61a6"},
-    {file = "oracledb-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:796b900fe85af572ff3d7227372ca3a2edd5f756e538e95ffbfc689df3881696"},
-    {file = "oracledb-1.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f669d7fa78a865d10ad9840a2cb6958b395c572c119ff51489a4a738302727e"},
-    {file = "oracledb-1.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5e20ed24335c59f42003750be3063f3d75f371af35eff47cc9177e9a4193af2"},
-    {file = "oracledb-1.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb49ebd84d65080703ea8a2b2edde3ac27a6fdc9c491db2dbde0b960f40e3c10"},
-    {file = "oracledb-1.3.2-cp39-cp39-win32.whl", hash = "sha256:022a6631ac779f0d600870fea1f7600a03eabcb4609138e91ac77b8126a9373b"},
-    {file = "oracledb-1.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:4fdeb8b2158d5fb93451d57152f9cfb25f0d876dcbb90305133267196c9efd84"},
-    {file = "oracledb-1.3.2.tar.gz", hash = "sha256:bb3c391c167b5778ddb15a7538a2b36db5c9b88a50c86c61781ca9ff302bb643"},
+    {file = "oracledb-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1fba71bbc0ec8fc806236a30d1212d2f516519c0658f0022f3d5fb593cb4e9b2"},
+    {file = "oracledb-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f1d7c4d3d68572fa0ef3d3973dd0905c4f30e31d91de6a8da771223937fefa9"},
+    {file = "oracledb-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5b9542d77b86c80dcc0314458cb15619831c06f232bbdbd77863f8ab5921b3"},
+    {file = "oracledb-1.4.2-cp310-cp310-win32.whl", hash = "sha256:db99de736ed7996bd428ad0a4eb154543d6dd4add2a2b67b46a51cbf761e01ec"},
+    {file = "oracledb-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:facf47d6787a0d2ab7cf8dfa68572ea4a3f1cb022843a8ff3b9f87d75ba7c815"},
+    {file = "oracledb-1.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56667754b7d4add421edebb624e772f64f3a192e9ff5a7d3ed32d79ed1d37a01"},
+    {file = "oracledb-1.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abc152418518fb8e433403afe39b6d2a71faa8653316d6a8e1853bb152584e84"},
+    {file = "oracledb-1.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2152dffc586fd7544bd0dd883db4ab93cf17a0bfece8f4d305353f4bdebc627c"},
+    {file = "oracledb-1.4.2-cp311-cp311-win32.whl", hash = "sha256:99d08c406752c38c3f3e863db372d1f74adb4d23dd6a34437ddea9fe3f437a37"},
+    {file = "oracledb-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5ab88775074b6a758951fea09e53a824343ab53cb84e5a662a52ef5c5799a2b"},
+    {file = "oracledb-1.4.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e482cd62cf2c1eb9d655f95d5e87e7903ad83fd759b3c2b2b634d4480ff9d086"},
+    {file = "oracledb-1.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69302569a08a9bc136c1032d72222545271100460d1dcde7f9bb8fa928efb11f"},
+    {file = "oracledb-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21f74ed6de46465020b23f8fe765f246d835e121482009f7389cb693686f3151"},
+    {file = "oracledb-1.4.2-cp312-cp312-win32.whl", hash = "sha256:7e13acc1dab125506b87e536d0e3ed2e1482b61cadae7ba140471c4d2b9315e3"},
+    {file = "oracledb-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:dea6a0c5150ebb52c0ba617b636d2f5af40fef1d0901e3df3f3f0bcc03359ac7"},
+    {file = "oracledb-1.4.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecdebcca26e9964903dd36d01bb95bbf64cd4403a741f8ec7ad9122073fb30a8"},
+    {file = "oracledb-1.4.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52a8b99e00cda8de6ca8e887e00dfb60753eab2b98cf1812c7fb7033e757b5fc"},
+    {file = "oracledb-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d77808966802c36995ac81107ee8e3ec188030fc81f753d813edbb604c8bf584"},
+    {file = "oracledb-1.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420fd1571426bd4d645849977c4660dcb953387166684d55e5032abf25aac2ed"},
+    {file = "oracledb-1.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6028c8edf53fa13781cdd9324c02e41d6072f5b753e6c6a37c1e1081587e6b2"},
+    {file = "oracledb-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:2154d4c71f421d2be8fbcbd51174e6fc7194346e74e903882c6be43e6ac03fed"},
+    {file = "oracledb-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c99e5ade66a04e57b8ff98dd9e1a3068426835446c76d7fa6b8d2100f1d32a52"},
+    {file = "oracledb-1.4.2-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:34fabe0b96a4ca3369bfd3edf570455aad16d64e62563bb493cd4870c51724e3"},
+    {file = "oracledb-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf56e92ad93b3822918dec26f6c0948904a3ac5ab49a8246c1e48c65933bbcaa"},
+    {file = "oracledb-1.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5050aff415b9ef516b271f52e667f52dde9f236bd36ffb6c2e080b9011e6d19d"},
+    {file = "oracledb-1.4.2-cp38-cp38-win32.whl", hash = "sha256:1d21b92854b8ea7fd6b216743e7e8585b666031ca2d2b3700c23b62710648c03"},
+    {file = "oracledb-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:87243baec69b71b3bdb2b9e3962812d66f75953ae1773251c8db510426470761"},
+    {file = "oracledb-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a8e8b306d8032436d0619191021379f298215cc90ae1d9cc0e064529d5cfbb61"},
+    {file = "oracledb-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a31bfbbfec42e9c4f518c9fb4c0a70dda7154ae01539a697688107a75047297f"},
+    {file = "oracledb-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29b0188a0ecf4951114c5bdd5a252725f9637fe2a7786e454036720d5f6aa9bf"},
+    {file = "oracledb-1.4.2-cp39-cp39-win32.whl", hash = "sha256:035432c89f92ad1b36cd9ce8cd70ddcbe7a2b8e281d8951e77136a977c82a135"},
+    {file = "oracledb-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:c839cf0f3f90b953243dc65debcfc66dfbd3c885ff9fd2e68d16de986d25e01c"},
+    {file = "oracledb-1.4.2.tar.gz", hash = "sha256:e28ed9046f2735dc2dd5bbcdf3667f284e384e0ec7eed3eeb3798fa8a7d47e36"},
 ]
 
 [package.dependencies]
 cryptography = ">=3.2.1"
 
-[[package]]
-name = "oscrypto"
-version = "1.3.0"
-description = "TLS (SSL) sockets, key generation, encryption, decryption, signing, verification and KDFs using the OS crypto libraries. Does not require a compiler, and relies on the OS for patching. Works on Windows, OS X and Linux/BSD."
-optional = false
-python-versions = "*"
-files = [
-    {file = "oscrypto-1.3.0-py2.py3-none-any.whl", hash = "sha256:2b2f1d2d42ec152ca90ccb5682f3e051fb55986e1b170ebde472b133713e7085"},
-    {file = "oscrypto-1.3.0.tar.gz", hash = "sha256:6f5fef59cb5b3708321db7cca56aed8ad7e662853351e7991fcf60ec606d47a4"},
-]
-
-[package.dependencies]
-asn1crypto = ">=1.5.1"
-
 [[package]]
 name = "packaging"
-version = "21.3"
+version = "23.2"
 description = "Core utilities for Python packages"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
-    {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
+    {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
+    {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
 ]
 
-[package.dependencies]
-pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
-
 [[package]]
 name = "parameterized"
-version = "0.8.1"
+version = "0.9.0"
 description = "Parameterized testing with any Python test framework"
 optional = false
-python-versions = "*"
+python-versions = ">=3.7"
 files = [
-    {file = "parameterized-0.8.1-py2.py3-none-any.whl", hash = "sha256:9cbb0b69a03e8695d68b3399a8a5825200976536fe1cb79db60ed6a4c8c9efe9"},
-    {file = "parameterized-0.8.1.tar.gz", hash = "sha256:41bbff37d6186430f77f900d777e5bb6a24928a1c46fb1de692f8b52b8833b5c"},
+    {file = "parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b"},
+    {file = "parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1"},
 ]
 
 [package.extras]
@@ -1238,18 +1292,15 @@ dev = ["jinja2"]
 
 [[package]]
 name = "parsedatetime"
-version = "2.4"
+version = "2.6"
 description = "Parse human-readable date/time text."
 optional = false
 python-versions = "*"
 files = [
-    {file = "parsedatetime-2.4-py2-none-any.whl", hash = "sha256:9ee3529454bf35c40a77115f5a596771e59e1aee8c53306f346c461b8e913094"},
-    {file = "parsedatetime-2.4.tar.gz", hash = "sha256:3d817c58fb9570d1eec1dd46fa9448cd644eeed4fb612684b02dfda3a79cb84b"},
+    {file = "parsedatetime-2.6-py3-none-any.whl", hash = "sha256:cb96edd7016872f58479e35879294258c71437195760746faffedb692aef000b"},
+    {file = "parsedatetime-2.6.tar.gz", hash = "sha256:4cb368fbb18a0b7231f4d76119165451c8d2e35951455dfee97c62a87b04d455"},
 ]
 
-[package.dependencies]
-future = "*"
-
 [[package]]
 name = "pathspec"
 version = "0.11.2"
@@ -1261,6 +1312,17 @@ files = [
     {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
 ]
 
+[[package]]
+name = "pkgutil-resolve-name"
+version = "1.3.10"
+description = "Resolve a name to an object."
+optional = false
+python-versions = ">=3.6"
+files = [
+    {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"},
+    {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"},
+]
+
 [[package]]
 name = "platformdirs"
 version = "3.11.0"
@@ -1343,13 +1405,13 @@ tests = ["google-auth", "httpretty", "pytest", "pytest-runner", "requests-kerber
 
 [[package]]
 name = "prompt-toolkit"
-version = "3.0.36"
+version = "3.0.43"
 description = "Library for building powerful interactive command lines in Python"
 optional = false
-python-versions = ">=3.6.2"
+python-versions = ">=3.7.0"
 files = [
-    {file = "prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"},
-    {file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"},
+    {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"},
+    {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"},
 ]
 
 [package.dependencies]
@@ -1357,46 +1419,44 @@ wcwidth = "*"
 
 [[package]]
 name = "protobuf"
-version = "4.22.3"
+version = "4.25.1"
 description = ""
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "protobuf-4.22.3-cp310-abi3-win32.whl", hash = "sha256:8b54f56d13ae4a3ec140076c9d937221f887c8f64954673d46f63751209e839a"},
-    {file = "protobuf-4.22.3-cp310-abi3-win_amd64.whl", hash = "sha256:7760730063329d42a9d4c4573b804289b738d4931e363ffbe684716b796bde51"},
-    {file = "protobuf-4.22.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:d14fc1a41d1a1909998e8aff7e80d2a7ae14772c4a70e4bf7db8a36690b54425"},
-    {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:70659847ee57a5262a65954538088a1d72dfc3e9882695cab9f0c54ffe71663b"},
-    {file = "protobuf-4.22.3-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:13233ee2b9d3bd9a5f216c1fa2c321cd564b93d8f2e4f521a85b585447747997"},
-    {file = "protobuf-4.22.3-cp37-cp37m-win32.whl", hash = "sha256:ecae944c6c2ce50dda6bf76ef5496196aeb1b85acb95df5843cd812615ec4b61"},
-    {file = "protobuf-4.22.3-cp37-cp37m-win_amd64.whl", hash = "sha256:d4b66266965598ff4c291416be429cef7989d8fae88b55b62095a2331511b3fa"},
-    {file = "protobuf-4.22.3-cp38-cp38-win32.whl", hash = "sha256:f08aa300b67f1c012100d8eb62d47129e53d1150f4469fd78a29fa3cb68c66f2"},
-    {file = "protobuf-4.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:f2f4710543abec186aee332d6852ef5ae7ce2e9e807a3da570f36de5a732d88e"},
-    {file = "protobuf-4.22.3-cp39-cp39-win32.whl", hash = "sha256:7cf56e31907c532e460bb62010a513408e6cdf5b03fb2611e4b67ed398ad046d"},
-    {file = "protobuf-4.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:e0e630d8e6a79f48c557cd1835865b593d0547dce221c66ed1b827de59c66c97"},
-    {file = "protobuf-4.22.3-py3-none-any.whl", hash = "sha256:52f0a78141078077cfe15fe333ac3e3a077420b9a3f5d1bf9b5fe9d286b4d881"},
-    {file = "protobuf-4.22.3.tar.gz", hash = "sha256:23452f2fdea754a8251d0fc88c0317735ae47217e0d27bf330a30eec2848811a"},
+    {file = "protobuf-4.25.1-cp310-abi3-win32.whl", hash = "sha256:193f50a6ab78a970c9b4f148e7c750cfde64f59815e86f686c22e26b4fe01ce7"},
+    {file = "protobuf-4.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:3497c1af9f2526962f09329fd61a36566305e6c72da2590ae0d7d1322818843b"},
+    {file = "protobuf-4.25.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:0bf384e75b92c42830c0a679b0cd4d6e2b36ae0cf3dbb1e1dfdda48a244f4bcd"},
+    {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:0f881b589ff449bf0b931a711926e9ddaad3b35089cc039ce1af50b21a4ae8cb"},
+    {file = "protobuf-4.25.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:ca37bf6a6d0046272c152eea90d2e4ef34593aaa32e8873fc14c16440f22d4b7"},
+    {file = "protobuf-4.25.1-cp38-cp38-win32.whl", hash = "sha256:abc0525ae2689a8000837729eef7883b9391cd6aa7950249dcf5a4ede230d5dd"},
+    {file = "protobuf-4.25.1-cp38-cp38-win_amd64.whl", hash = "sha256:1484f9e692091450e7edf418c939e15bfc8fc68856e36ce399aed6889dae8bb0"},
+    {file = "protobuf-4.25.1-cp39-cp39-win32.whl", hash = "sha256:8bdbeaddaac52d15c6dce38c71b03038ef7772b977847eb6d374fc86636fa510"},
+    {file = "protobuf-4.25.1-cp39-cp39-win_amd64.whl", hash = "sha256:becc576b7e6b553d22cbdf418686ee4daa443d7217999125c045ad56322dda10"},
+    {file = "protobuf-4.25.1-py3-none-any.whl", hash = "sha256:a19731d5e83ae4737bb2a089605e636077ac001d18781b3cf489b9546c7c80d6"},
+    {file = "protobuf-4.25.1.tar.gz", hash = "sha256:57d65074b4f5baa4ab5da1605c02be90ac20c8b40fb137d6a8df9f416b0d0ce2"},
 ]
 
 [[package]]
 name = "psycopg2"
-version = "2.9.5"
+version = "2.9.9"
 description = "psycopg2 - Python-PostgreSQL Database Adapter"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "psycopg2-2.9.5-cp310-cp310-win32.whl", hash = "sha256:d3ef67e630b0de0779c42912fe2cbae3805ebaba30cda27fea2a3de650a9414f"},
-    {file = "psycopg2-2.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:4cb9936316d88bfab614666eb9e32995e794ed0f8f6b3b718666c22819c1d7ee"},
-    {file = "psycopg2-2.9.5-cp311-cp311-win32.whl", hash = "sha256:093e3894d2d3c592ab0945d9eba9d139c139664dcf83a1c440b8a7aa9bb21955"},
-    {file = "psycopg2-2.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:920bf418000dd17669d2904472efeab2b20546efd0548139618f8fa305d1d7ad"},
-    {file = "psycopg2-2.9.5-cp36-cp36m-win32.whl", hash = "sha256:b9ac1b0d8ecc49e05e4e182694f418d27f3aedcfca854ebd6c05bb1cffa10d6d"},
-    {file = "psycopg2-2.9.5-cp36-cp36m-win_amd64.whl", hash = "sha256:fc04dd5189b90d825509caa510f20d1d504761e78b8dfb95a0ede180f71d50e5"},
-    {file = "psycopg2-2.9.5-cp37-cp37m-win32.whl", hash = "sha256:922cc5f0b98a5f2b1ff481f5551b95cd04580fd6f0c72d9b22e6c0145a4840e0"},
-    {file = "psycopg2-2.9.5-cp37-cp37m-win_amd64.whl", hash = "sha256:1e5a38aa85bd660c53947bd28aeaafb6a97d70423606f1ccb044a03a1203fe4a"},
-    {file = "psycopg2-2.9.5-cp38-cp38-win32.whl", hash = "sha256:f5b6320dbc3cf6cfb9f25308286f9f7ab464e65cfb105b64cc9c52831748ced2"},
-    {file = "psycopg2-2.9.5-cp38-cp38-win_amd64.whl", hash = "sha256:1a5c7d7d577e0eabfcf15eb87d1e19314c8c4f0e722a301f98e0e3a65e238b4e"},
-    {file = "psycopg2-2.9.5-cp39-cp39-win32.whl", hash = "sha256:322fd5fca0b1113677089d4ebd5222c964b1760e361f151cbb2706c4912112c5"},
-    {file = "psycopg2-2.9.5-cp39-cp39-win_amd64.whl", hash = "sha256:190d51e8c1b25a47484e52a79638a8182451d6f6dff99f26ad9bd81e5359a0fa"},
-    {file = "psycopg2-2.9.5.tar.gz", hash = "sha256:a5246d2e683a972e2187a8714b5c2cf8156c064629f9a9b1a873c1730d9e245a"},
+    {file = "psycopg2-2.9.9-cp310-cp310-win32.whl", hash = "sha256:38a8dcc6856f569068b47de286b472b7c473ac7977243593a288ebce0dc89516"},
+    {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
+    {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
+    {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
+    {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
+    {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
+    {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
+    {file = "psycopg2-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:bac58c024c9922c23550af2a581998624d6e02350f4ae9c5f0bc642c633a2d5e"},
+    {file = "psycopg2-2.9.9-cp39-cp39-win32.whl", hash = "sha256:c92811b2d4c9b6ea0285942b2e7cac98a59e166d59c588fe5cfe1eda58e72d59"},
+    {file = "psycopg2-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:de80739447af31525feddeb8effd640782cf5998e1a4e9192ebdf829717e3913"},
+    {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"},
 ]
 
 [[package]]
@@ -1410,41 +1470,6 @@ files = [
     {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
 ]
 
-[[package]]
-name = "pycryptodomex"
-version = "3.16.0"
-description = "Cryptographic library for Python"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-files = [
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b3d04c00d777c36972b539fb79958790126847d84ec0129fce1efef250bfe3ce"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e5a670919076b71522c7d567a9043f66f14b202414a63c3a078b5831ae342c03"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ce338a9703f54b2305a408fc9890eb966b727ce72b69f225898bb4e9d9ed3f1f"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:a1c0ae7123448ecb034c75c713189cb00ebe2d415b11682865b6c54d200d9c93"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-win32.whl", hash = "sha256:8851585ff19871e5d69e1790f4ca5f6fd1699d6b8b14413b472a4c0dbc7ea780"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27m-win_amd64.whl", hash = "sha256:8dd2d9e3c617d0712ed781a77efd84ea579e76c5f9b2a4bc0b684ebeddf868b2"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2ad9bb86b355b6104796567dd44c215b3dc953ef2fae5e0bdfb8516731df92cf"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e25a2f5667d91795f9417cb856f6df724ccdb0cdd5cbadb212ee9bf43946e9f8"},
-    {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b0789a8490114a2936ed77c87792cfe77582c829cb43a6d86ede0f9624ba8aa3"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0da835af786fdd1c9930994c78b23e88d816dc3f99aa977284a21bbc26d19735"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:22aed0868622d95179217c298e37ed7410025c7b29dac236d3230617d1e4ed56"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1619087fb5b31510b0b0b058a54f001a5ffd91e6ffee220d9913064519c6a69d"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:70288d9bfe16b2fd0d20b6c365db614428f1bcde7b20d56e74cf88ade905d9eb"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7993d26dae4d83b8f4ce605bb0aecb8bee330bb3c95475ef06f3694403621e71"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1cda60207be8c1cf0b84b9138f9e3ca29335013d2b690774a5e94678ff29659a"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:04610536921c1ec7adba158ef570348550c9f3a40bc24be9f8da2ef7ab387981"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-win32.whl", hash = "sha256:daa67f5ebb6fbf1ee9c90decaa06ca7fc88a548864e5e484d52b0920a57fe8a5"},
-    {file = "pycryptodomex-3.16.0-cp35-abi3-win_amd64.whl", hash = "sha256:231dc8008cbdd1ae0e34645d4523da2dbc7a88c325f0d4a59635a86ee25b41dd"},
-    {file = "pycryptodomex-3.16.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:4dbbe18cc232b5980c7633972ae5417d0df76fe89e7db246eefd17ef4d8e6d7a"},
-    {file = "pycryptodomex-3.16.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:893f8a97d533c66cc3a56e60dd3ed40a3494ddb4aafa7e026429a08772f8a849"},
-    {file = "pycryptodomex-3.16.0-pp27-pypy_73-win32.whl", hash = "sha256:6a465e4f856d2a4f2a311807030c89166529ccf7ccc65bef398de045d49144b6"},
-    {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba57ac7861fd2c837cdb33daf822f2a052ff57dd769a2107807f52a36d0e8d38"},
-    {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f2b971a7b877348a27dcfd0e772a0343fb818df00b74078e91c008632284137d"},
-    {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e2453162f473c1eae4826eb10cd7bce19b5facac86d17fb5f29a570fde145abd"},
-    {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0ba28aa97cdd3ff5ed1a4f2b7f5cd04e721166bd75bd2b929e2734433882b583"},
-    {file = "pycryptodomex-3.16.0.tar.gz", hash = "sha256:e9ba9d8ed638733c9e95664470b71d624a6def149e2db6cc52c1aca5a6a2df1d"},
-]
-
 [[package]]
 name = "pydantic"
 version = "1.10.12"
@@ -1499,27 +1524,28 @@ email = ["email-validator (>=1.0.3)"]
 
 [[package]]
 name = "pygments"
-version = "2.15.1"
+version = "2.17.2"
 description = "Pygments is a syntax highlighting package written in Python."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "Pygments-2.15.1-py3-none-any.whl", hash = "sha256:db2db3deb4b4179f399a09054b023b6a586b76499d36965813c71aa8ed7b5fd1"},
-    {file = "Pygments-2.15.1.tar.gz", hash = "sha256:8ace4d3c1dd481894b2005f560ead0f9f19ee64fe983366be1a21e171d12775c"},
+    {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"},
+    {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"},
 ]
 
 [package.extras]
 plugins = ["importlib-metadata"]
+windows-terminal = ["colorama (>=0.4.6)"]
 
 [[package]]
-name = "PyJWT"
-version = "2.6.0"
+name = "pyjwt"
+version = "2.8.0"
 description = "JSON Web Token implementation in Python"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "PyJWT-2.6.0-py3-none-any.whl", hash = "sha256:d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14"},
-    {file = "PyJWT-2.6.0.tar.gz", hash = "sha256:69285c7e31fc44f68a1feb309e948e0df53259d579295e6cfe2b1792329f05fd"},
+    {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"},
+    {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"},
 ]
 
 [package.extras]
@@ -1574,72 +1600,22 @@ files = [
 
 [[package]]
 name = "pyopenssl"
-version = "22.0.0"
+version = "23.3.0"
 description = "Python wrapper module around the OpenSSL library"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 files = [
-    {file = "pyOpenSSL-22.0.0-py2.py3-none-any.whl", hash = "sha256:ea252b38c87425b64116f808355e8da644ef9b07e429398bfece610f893ee2e0"},
-    {file = "pyOpenSSL-22.0.0.tar.gz", hash = "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf"},
+    {file = "pyOpenSSL-23.3.0-py3-none-any.whl", hash = "sha256:6756834481d9ed5470f4a9393455154bc92fe7a64b7bc6ee2c804e78c52099b2"},
+    {file = "pyOpenSSL-23.3.0.tar.gz", hash = "sha256:6b2cba5cc46e822750ec3e5a81ee12819850b11303630d575e98108a079c2b12"},
 ]
 
 [package.dependencies]
-cryptography = ">=35.0"
+cryptography = ">=41.0.5,<42"
 
 [package.extras]
-docs = ["sphinx", "sphinx-rtd-theme"]
+docs = ["sphinx (!=5.2.0,!=5.2.0.post0,!=7.2.5)", "sphinx-rtd-theme"]
 test = ["flaky", "pretend", "pytest (>=3.0.1)"]
 
-[[package]]
-name = "pyparsing"
-version = "3.0.9"
-description = "pyparsing module - Classes and methods to define and execute parsing grammars"
-optional = false
-python-versions = ">=3.6.8"
-files = [
-    {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
-    {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
-]
-
-[package.extras]
-diagrams = ["jinja2", "railroad-diagrams"]
-
-[[package]]
-name = "pyrsistent"
-version = "0.19.3"
-description = "Persistent/Functional/Immutable data structures"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "pyrsistent-0.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:20460ac0ea439a3e79caa1dbd560344b64ed75e85d8703943e0b66c2a6150e4a"},
-    {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c18264cb84b5e68e7085a43723f9e4c1fd1d935ab240ce02c0324a8e01ccb64"},
-    {file = "pyrsistent-0.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b774f9288dda8d425adb6544e5903f1fb6c273ab3128a355c6b972b7df39dcf"},
-    {file = "pyrsistent-0.19.3-cp310-cp310-win32.whl", hash = "sha256:5a474fb80f5e0d6c9394d8db0fc19e90fa540b82ee52dba7d246a7791712f74a"},
-    {file = "pyrsistent-0.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:49c32f216c17148695ca0e02a5c521e28a4ee6c5089f97e34fe24163113722da"},
-    {file = "pyrsistent-0.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f0774bf48631f3a20471dd7c5989657b639fd2d285b861237ea9e82c36a415a9"},
-    {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab2204234c0ecd8b9368dbd6a53e83c3d4f3cab10ecaf6d0e772f456c442393"},
-    {file = "pyrsistent-0.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e42296a09e83028b3476f7073fcb69ffebac0e66dbbfd1bd847d61f74db30f19"},
-    {file = "pyrsistent-0.19.3-cp311-cp311-win32.whl", hash = "sha256:64220c429e42a7150f4bfd280f6f4bb2850f95956bde93c6fda1b70507af6ef3"},
-    {file = "pyrsistent-0.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:016ad1afadf318eb7911baa24b049909f7f3bb2c5b1ed7b6a8f21db21ea3faa8"},
-    {file = "pyrsistent-0.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4db1bd596fefd66b296a3d5d943c94f4fac5bcd13e99bffe2ba6a759d959a28"},
-    {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aeda827381f5e5d65cced3024126529ddc4289d944f75e090572c77ceb19adbf"},
-    {file = "pyrsistent-0.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42ac0b2f44607eb92ae88609eda931a4f0dfa03038c44c772e07f43e738bcac9"},
-    {file = "pyrsistent-0.19.3-cp37-cp37m-win32.whl", hash = "sha256:e8f2b814a3dc6225964fa03d8582c6e0b6650d68a232df41e3cc1b66a5d2f8d1"},
-    {file = "pyrsistent-0.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9bb60a40a0ab9aba40a59f68214eed5a29c6274c83b2cc206a359c4a89fa41b"},
-    {file = "pyrsistent-0.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a2471f3f8693101975b1ff85ffd19bb7ca7dd7c38f8a81701f67d6b4f97b87d8"},
-    {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc5d149f31706762c1f8bda2e8c4f8fead6e80312e3692619a75301d3dbb819a"},
-    {file = "pyrsistent-0.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3311cb4237a341aa52ab8448c27e3a9931e2ee09561ad150ba94e4cfd3fc888c"},
-    {file = "pyrsistent-0.19.3-cp38-cp38-win32.whl", hash = "sha256:f0e7c4b2f77593871e918be000b96c8107da48444d57005b6a6bc61fb4331b2c"},
-    {file = "pyrsistent-0.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:c147257a92374fde8498491f53ffa8f4822cd70c0d85037e09028e478cababb7"},
-    {file = "pyrsistent-0.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b735e538f74ec31378f5a1e3886a26d2ca6351106b4dfde376a26fc32a044edc"},
-    {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99abb85579e2165bd8522f0c0138864da97847875ecbd45f3e7e2af569bfc6f2"},
-    {file = "pyrsistent-0.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a8cb235fa6d3fd7aae6a4f1429bbb1fec1577d978098da1252f0489937786f3"},
-    {file = "pyrsistent-0.19.3-cp39-cp39-win32.whl", hash = "sha256:c74bed51f9b41c48366a286395c67f4e894374306b197e62810e0fdaf2364da2"},
-    {file = "pyrsistent-0.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:878433581fc23e906d947a6814336eee031a00e6defba224234169ae3d3d6a98"},
-    {file = "pyrsistent-0.19.3-py3-none-any.whl", hash = "sha256:ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64"},
-    {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"},
-]
-
 [[package]]
 name = "python-dateutil"
 version = "2.8.2"
@@ -1656,13 +1632,13 @@ six = ">=1.5"
 
 [[package]]
 name = "python-slugify"
-version = "7.0.0"
+version = "8.0.1"
 description = "A Python slugify application that also handles Unicode"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "python-slugify-7.0.0.tar.gz", hash = "sha256:7a0f21a39fa6c1c4bf2e5984c9b9ae944483fd10b54804cb0e23a3ccd4954f0b"},
-    {file = "python_slugify-7.0.0-py2.py3-none-any.whl", hash = "sha256:003aee64f9fd955d111549f96c4b58a3f40b9319383c70fad6277a4974bbf570"},
+    {file = "python-slugify-8.0.1.tar.gz", hash = "sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27"},
+    {file = "python_slugify-8.0.1-py2.py3-none-any.whl", hash = "sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395"},
 ]
 
 [package.dependencies]
@@ -1684,106 +1660,116 @@ files = [
 
 [[package]]
 name = "pytz"
-version = "2022.6"
+version = "2023.3.post1"
 description = "World timezone definitions, modern and historical"
 optional = false
 python-versions = "*"
 files = [
-    {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"},
-    {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"},
+    {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"},
+    {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"},
 ]
 
-[[package]]
-name = "pytz-deprecation-shim"
-version = "0.1.0.post0"
-description = "Shims to make deprecation of pytz easier"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
-files = [
-    {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
-    {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
-]
-
-[package.dependencies]
-"backports.zoneinfo" = {version = "*", markers = "python_version >= \"3.6\" and python_version < \"3.9\""}
-tzdata = {version = "*", markers = "python_version >= \"3.6\""}
-
 [[package]]
 name = "pywin32-ctypes"
-version = "0.2.0"
-description = ""
+version = "0.2.2"
+description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
 optional = false
-python-versions = "*"
+python-versions = ">=3.6"
 files = [
-    {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"},
-    {file = "pywin32_ctypes-0.2.0-py2.py3-none-any.whl", hash = "sha256:9dc2d991b3479cc2df15930958b674a48a227d5361d413827a4cfd0b5876fc98"},
+    {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
+    {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
 ]
 
 [[package]]
 name = "pyyaml"
-version = "6.0"
+version = "6.0.1"
 description = "YAML parser and emitter for Python"
 optional = false
 python-versions = ">=3.6"
 files = [
-    {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
-    {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
-    {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
-    {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
-    {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
-    {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
-    {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
-    {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
-    {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
-    {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
-    {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
-    {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
-    {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
-    {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
-    {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
-    {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
-    {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
-    {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
-    {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
-    {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
-    {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
-    {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
-    {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
-    {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
+    {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+    {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+    {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
+    {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+    {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+    {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+    {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+    {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
+    {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+    {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+    {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
+    {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+    {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
+    {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
+    {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
+    {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+    {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+    {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+    {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+    {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
+    {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+    {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+    {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+    {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+    {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
+    {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+    {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+    {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[[package]]
+name = "referencing"
+version = "0.32.0"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "referencing-0.32.0-py3-none-any.whl", hash = "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99"},
+    {file = "referencing-0.32.0.tar.gz", hash = "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161"},
 ]
 
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+
 [[package]]
 name = "requests"
-version = "2.28.1"
+version = "2.31.0"
 description = "Python HTTP for Humans."
 optional = false
-python-versions = ">=3.7, <4"
+python-versions = ">=3.7"
 files = [
-    {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
-    {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
+    {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
+    {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
 ]
 
 [package.dependencies]
 certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<3"
+charset-normalizer = ">=2,<4"
 idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<1.27"
+urllib3 = ">=1.21.1,<3"
 
 [package.extras]
 socks = ["PySocks (>=1.5.6,!=1.5.7)"]
@@ -1791,46 +1777,155 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 
 [[package]]
 name = "rich"
-version = "12.0.1"
+version = "13.7.0"
 description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
 optional = false
-python-versions = ">=3.6.2,<4.0.0"
+python-versions = ">=3.7.0"
 files = [
-    {file = "rich-12.0.1-py3-none-any.whl", hash = "sha256:ce5c714e984a2d185399e4e1dd1f8b2feacb7cecfc576f1522425643a36a57ea"},
-    {file = "rich-12.0.1.tar.gz", hash = "sha256:3fba9dd15ebe048e2795a02ac19baee79dc12cc50b074ef70f2958cd651b59a9"},
+    {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
+    {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
 ]
 
 [package.dependencies]
-commonmark = ">=0.9.0,<0.10.0"
-pygments = ">=2.6.0,<3.0.0"
+markdown-it-py = ">=2.2.0"
+pygments = ">=2.13.0,<3.0.0"
+typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
 
 [package.extras]
-jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
+jupyter = ["ipywidgets (>=7.5.1,<9)"]
+
+[[package]]
+name = "rpds-py"
+version = "0.15.2"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.8"
+files = [
+    {file = "rpds_py-0.15.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:337a8653fb11d2fbe7157c961cc78cb3c161d98cf44410ace9a3dc2db4fad882"},
+    {file = "rpds_py-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:813a65f95bfcb7c8f2a70dd6add9b51e9accc3bdb3e03d0ff7a9e6a2d3e174bf"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:082e0e55d73690ffb4da4352d1b5bbe1b5c6034eb9dc8c91aa2a3ee15f70d3e2"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5595c80dd03d7e6c6afb73f3594bf3379a7d79fa57164b591d012d4b71d6ac4c"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb10bb720348fe1647a94eb605accb9ef6a9b1875d8845f9e763d9d71a706387"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53304cc14b1d94487d70086e1cb0cb4c29ec6da994d58ae84a4d7e78c6a6d04d"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d64a657de7aae8db2da60dc0c9e4638a0c3893b4d60101fd564a3362b2bfeb34"},
+    {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ee40206d1d6e95eaa2b7b919195e3689a5cf6ded730632de7f187f35a1b6052c"},
+    {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1607cda6129f815493a3c184492acb5ae4aa6ed61d3a1b3663aa9824ed26f7ac"},
+    {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3e6e2e502c4043c52a99316d89dc49f416acda5b0c6886e0dd8ea7bb35859e8"},
+    {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:044f6f46d62444800402851afa3c3ae50141f12013060c1a3a0677e013310d6d"},
+    {file = "rpds_py-0.15.2-cp310-none-win32.whl", hash = "sha256:c827a931c6b57f50f1bb5de400dcfb00bad8117e3753e80b96adb72d9d811514"},
+    {file = "rpds_py-0.15.2-cp310-none-win_amd64.whl", hash = "sha256:3bbc89ce2a219662ea142f0abcf8d43f04a41d5b1880be17a794c39f0d609cb0"},
+    {file = "rpds_py-0.15.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:1fd0f0b1ccd7d537b858a56355a250108df692102e08aa2036e1a094fd78b2dc"},
+    {file = "rpds_py-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b414ef79f1f06fb90b5165db8aef77512c1a5e3ed1b4807da8476b7e2c853283"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c31272c674f725dfe0f343d73b0abe8c878c646967ec1c6106122faae1efc15b"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6945c2d61c42bb7e818677f43638675b8c1c43e858b67a96df3eb2426a86c9d"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02744236ac1895d7be837878e707a5c35fb8edc5137602f253b63623d7ad5c8c"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2181e86d4e1cdf49a7320cb72a36c45efcb7670d0a88f09fd2d3a7967c0540fd"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a8ff8e809da81363bffca2b965cb6e4bf6056b495fc3f078467d1f8266fe27f"},
+    {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97532802f14d383f37d603a56e226909f825a83ff298dc1b6697de00d2243999"},
+    {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:13716e53627ad97babf72ac9e01cf9a7d4af2f75dd5ed7b323a7a9520e948282"},
+    {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2f1f295a5c28cfa74a7d48c95acc1c8a7acd49d7d9072040d4b694fe11cd7166"},
+    {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8ec464f20fe803ae00419bd1610934e3bda963aeba1e6181dfc9033dc7e8940c"},
+    {file = "rpds_py-0.15.2-cp311-none-win32.whl", hash = "sha256:b61d5096e75fd71018b25da50b82dd70ec39b5e15bb2134daf7eb7bbbc103644"},
+    {file = "rpds_py-0.15.2-cp311-none-win_amd64.whl", hash = "sha256:9d41ebb471a6f064c0d1c873c4f7dded733d16ca5db7d551fb04ff3805d87802"},
+    {file = "rpds_py-0.15.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:13ff62d3561a23c17341b4afc78e8fcfd799ab67c0b1ca32091d71383a98ba4b"},
+    {file = "rpds_py-0.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b70b45a40ad0798b69748b34d508259ef2bdc84fb2aad4048bc7c9cafb68ddb3"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ecbba7efd82bd2a4bb88aab7f984eb5470991c1347bdd1f35fb34ea28dba6e"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d38494a8d21c246c535b41ecdb2d562c4b933cf3d68de03e8bc43a0d41be652"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13152dfe7d7c27c40df8b99ac6aab12b978b546716e99f67e8a67a1d441acbc3"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:164fcee32f15d04d61568c9cb0d919e37ff3195919cd604039ff3053ada0461b"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a5122b17a4faf5d7a6d91fa67b479736c0cacc7afe791ddebb7163a8550b799"},
+    {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46b4f3d47d1033db569173be62365fbf7808c2bd3fb742314d251f130d90d44c"},
+    {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c61e42b4ceb9759727045765e87d51c1bb9f89987aca1fcc8a040232138cad1c"},
+    {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d2aa3ca9552f83b0b4fa6ca8c6ce08da6580f37e3e0ab7afac73a1cfdc230c0e"},
+    {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec19e823b4ccd87bd69e990879acbce9e961fc7aebe150156b8f4418d4b27b7f"},
+    {file = "rpds_py-0.15.2-cp312-none-win32.whl", hash = "sha256:afeabb382c1256a7477b739820bce7fe782bb807d82927102cee73e79b41b38b"},
+    {file = "rpds_py-0.15.2-cp312-none-win_amd64.whl", hash = "sha256:422b0901878a31ef167435c5ad46560362891816a76cc0d150683f3868a6f0d1"},
+    {file = "rpds_py-0.15.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:baf744e5f9d5ee6531deea443be78b36ed1cd36c65a0b95ea4e8d69fa0102268"},
+    {file = "rpds_py-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7e072f5da38d6428ba1fc1115d3cc0dae895df671cb04c70c019985e8c7606be"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f138f550b83554f5b344d6be35d3ed59348510edc3cb96f75309db6e9bfe8210"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b2a4cd924d0e2f4b1a68034abe4cadc73d69ad5f4cf02db6481c0d4d749f548f"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5eb05b654a41e0f81ab27a7c3e88b6590425eb3e934e1d533ecec5dc88a6ffff"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ee066a64f0d2ba45391cac15b3a70dcb549e968a117bd0500634754cfe0e5fc"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51a899792ee2c696072791e56b2020caff58b275abecbc9ae0cb71af0645c95"},
+    {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac2ac84a4950d627d84b61f082eba61314373cfab4b3c264b62efab02ababe83"},
+    {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:62b292fff4739c6be89e6a0240c02bda5a9066a339d90ab191cf66e9fdbdc193"},
+    {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:98ee201a52a7f65608e5494518932e1473fd43535f12cade0a1b4ab32737fe28"},
+    {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3d40fb3ca22e3d40f494d577441b263026a3bd8c97ae6ce89b2d3c4b39ac9581"},
+    {file = "rpds_py-0.15.2-cp38-none-win32.whl", hash = "sha256:30479a9f1fce47df56b07460b520f49fa2115ec2926d3b1303c85c81f8401ed1"},
+    {file = "rpds_py-0.15.2-cp38-none-win_amd64.whl", hash = "sha256:2df3d07a16a3bef0917b28cd564778fbb31f3ffa5b5e33584470e2d1b0f248f0"},
+    {file = "rpds_py-0.15.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:56b51ba29a18e5f5810224bcf00747ad931c0716e3c09a76b4a1edd3d4aba71f"},
+    {file = "rpds_py-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c11bc5814554b018f6c5d6ae0969e43766f81e995000b53a5d8c8057055e886"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2faa97212b0dc465afeedf49045cdd077f97be1188285e646a9f689cb5dfff9e"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:86c01299942b0f4b5b5f28c8701689181ad2eab852e65417172dbdd6c5b3ccc8"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd7d3608589072f63078b4063a6c536af832e76b0b3885f1bfe9e892abe6c207"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:938518a11780b39998179d07f31a4a468888123f9b00463842cd40f98191f4d3"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dccc623725d0b298f557d869a68496a2fd2a9e9c41107f234fa5f7a37d278ac"},
+    {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d46ee458452727a147d7897bb33886981ae1235775e05decae5d5d07f537695a"},
+    {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d9d7ebcd11ea76ba0feaae98485cd8e31467c3d7985210fab46983278214736b"},
+    {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8a5f574b92b3ee7d254e56d56e37ec0e1416acb1ae357c4956d76a1788dc58fb"},
+    {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3db0c998c92b909d7c90b66c965590d4f3cd86157176a6cf14aa1f867b77b889"},
+    {file = "rpds_py-0.15.2-cp39-none-win32.whl", hash = "sha256:bbc7421cbd28b4316d1d017db338039a7943f945c6f2bb15e1439b14b5682d28"},
+    {file = "rpds_py-0.15.2-cp39-none-win_amd64.whl", hash = "sha256:1c24e30d720c0009b6fb2e1905b025da56103c70a8b31b99138e4ed1c2a6c5b0"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e6fcd0a0f62f2997107f758bb372397b8d5fd5f39cc6dcb86f7cb98a2172d6c"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d800a8e2ac62db1b9ea5d6d1724f1a93c53907ca061de4d05ed94e8dfa79050c"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e09d017e3f4d9bd7d17a30d3f59e4d6d9ba2d2ced280eec2425e84112cf623f"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b88c3ab98556bc351b36d6208a6089de8c8db14a7f6e1f57f82a334bd2c18f0b"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f333bfe782a2d05a67cfaa0cc9cd68b36b39ee6acfe099f980541ed973a7093"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b629db53fe17e6ce478a969d30bd1d0e8b53238c46e3a9c9db39e8b65a9ef973"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485fbdd23becb822804ed05622907ee5c8e8a5f43f6f43894a45f463b2217045"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:893e38d0f4319dfa70c0f36381a37cc418985c87b11d9784365b1fff4fa6973b"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8ffdeb7dbd0160d4e391e1f857477e4762d00aa2199c294eb95dfb9451aa1d9f"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fc33267d58dfbb2361baed52668c5d8c15d24bc0372cecbb79fed77339b55e0d"},
+    {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2e7e5633577b3bd56bf3af2ef6ae3778bbafb83743989d57f0e7edbf6c0980e4"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8b9650f92251fdef843e74fc252cdfd6e3c700157ad686eeb0c6d7fdb2d11652"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:07a2e1d78d382f7181789713cdf0c16edbad4fe14fe1d115526cb6f0eef0daa3"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03f9c5875515820633bd7709a25c3e60c1ea9ad1c5d4030ce8a8c203309c36fd"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:580182fa5b269c2981e9ce9764367cb4edc81982ce289208d4607c203f44ffde"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa1e626c524d2c7972c0f3a8a575d654a3a9c008370dc2a97e46abd0eaa749b9"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae9d83a81b09ce3a817e2cbb23aabc07f86a3abc664c613cd283ce7a03541e95"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9235be95662559141934fced8197de6fee8c58870f36756b0584424b6d708393"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a72e00826a2b032dda3eb25aa3e3579c6d6773d22d8446089a57a123481cc46c"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ab095edf1d840a6a6a4307e1a5b907a299a94e7b90e75436ee770b8c35d22a25"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:3b79c63d29101cbaa53a517683557bb550462394fb91044cc5998dd2acff7340"},
+    {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:911e600e798374c0d86235e7ef19109cf865d1336942d398ff313375a25a93ba"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3cd61e759c4075510052d1eca5cddbd297fe1164efec14ef1fce3f09b974dfe4"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9d2ae79f31da5143e020a8d4fc74e1f0cbcb8011bdf97453c140aa616db51406"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e99d6510c8557510c220b865d966b105464740dcbebf9b79ecd4fbab30a13d9"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c43e1b89099279cc03eb1c725c5de12af6edcd2f78e2f8a022569efa639ada3"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac7187bee72384b9cfedf09a29a3b2b6e8815cc64c095cdc8b5e6aec81e9fd5f"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3423007fc0661827e06f8a185a3792c73dda41f30f3421562f210cf0c9e49569"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2974e6dff38afafd5ccf8f41cb8fc94600b3f4fd9b0a98f6ece6e2219e3158d5"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:93c18a1696a8e0388ed84b024fe1a188a26ba999b61d1d9a371318cb89885a8c"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:c7cd0841a586b7105513a7c8c3d5c276f3adc762a072d81ef7fae80632afad1e"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:709dc11af2f74ba89c68b1592368c6edcbccdb0a06ba77eb28c8fe08bb6997da"},
+    {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:fc066395e6332da1e7525d605b4c96055669f8336600bef8ac569d5226a7c76f"},
+    {file = "rpds_py-0.15.2.tar.gz", hash = "sha256:373b76eeb79e8c14f6d82cb1d4d5293f9e4059baec6c1b16dca7ad13b6131b39"},
+]
 
 [[package]]
 name = "ruff"
-version = "0.1.4"
+version = "0.1.8"
 description = "An extremely fast Python linter and code formatter, written in Rust."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "ruff-0.1.4-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:864958706b669cce31d629902175138ad8a069d99ca53514611521f532d91495"},
-    {file = "ruff-0.1.4-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:9fdd61883bb34317c788af87f4cd75dfee3a73f5ded714b77ba928e418d6e39e"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4eaca8c9cc39aa7f0f0d7b8fe24ecb51232d1bb620fc4441a61161be4a17539"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a9a1301dc43cbf633fb603242bccd0aaa34834750a14a4c1817e2e5c8d60de17"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e8db8ab6f100f02e28b3d713270c857d370b8d61871d5c7d1702ae411df683"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:80fea754eaae06335784b8ea053d6eb8e9aac75359ebddd6fee0858e87c8d510"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bc02a480d4bfffd163a723698da15d1a9aec2fced4c06f2a753f87f4ce6969c"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862811b403063765b03e716dac0fda8fdbe78b675cd947ed5873506448acea4"},
-    {file = "ruff-0.1.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58826efb8b3efbb59bb306f4b19640b7e366967a31c049d49311d9eb3a4c60cb"},
-    {file = "ruff-0.1.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:fdfd453fc91d9d86d6aaa33b1bafa69d114cf7421057868f0b79104079d3e66e"},
-    {file = "ruff-0.1.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e8791482d508bd0b36c76481ad3117987301b86072158bdb69d796503e1c84a8"},
-    {file = "ruff-0.1.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01206e361021426e3c1b7fba06ddcb20dbc5037d64f6841e5f2b21084dc51800"},
-    {file = "ruff-0.1.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:645591a613a42cb7e5c2b667cbefd3877b21e0252b59272ba7212c3d35a5819f"},
-    {file = "ruff-0.1.4-py3-none-win32.whl", hash = "sha256:99908ca2b3b85bffe7e1414275d004917d1e0dfc99d497ccd2ecd19ad115fd0d"},
-    {file = "ruff-0.1.4-py3-none-win_amd64.whl", hash = "sha256:1dfd6bf8f6ad0a4ac99333f437e0ec168989adc5d837ecd38ddb2cc4a2e3db8a"},
-    {file = "ruff-0.1.4-py3-none-win_arm64.whl", hash = "sha256:d98ae9ebf56444e18a3e3652b3383204748f73e247dea6caaf8b52d37e6b32da"},
-    {file = "ruff-0.1.4.tar.gz", hash = "sha256:21520ecca4cc555162068d87c747b8f95e1e95f8ecfcbbe59e8dd00710586315"},
+    {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7de792582f6e490ae6aef36a58d85df9f7a0cfd1b0d4fe6b4fb51803a3ac96fa"},
+    {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8e3255afd186c142eef4ec400d7826134f028a85da2146102a1172ecc7c3696"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff78a7583020da124dd0deb835ece1d87bb91762d40c514ee9b67a087940528b"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd8ee69b02e7bdefe1e5da2d5b6eaaddcf4f90859f00281b2333c0e3a0cc9cd6"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05b0ddd7ea25495e4115a43125e8a7ebed0aa043c3d432de7e7d6e8e8cd6448"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e6f08ca730f4dc1b76b473bdf30b1b37d42da379202a059eae54ec7fc1fbcfed"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f35960b02df6b827c1b903091bb14f4b003f6cf102705efc4ce78132a0aa5af3"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d076717c67b34c162da7c1a5bda16ffc205e0e0072c03745275e7eab888719f"},
+    {file = "ruff-0.1.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a21ab023124eafb7cef6d038f835cb1155cd5ea798edd8d9eb2f8b84be07d9"},
+    {file = "ruff-0.1.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ce697c463458555027dfb194cb96d26608abab920fa85213deb5edf26e026664"},
+    {file = "ruff-0.1.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db6cedd9ffed55548ab313ad718bc34582d394e27a7875b4b952c2d29c001b26"},
+    {file = "ruff-0.1.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:05ffe9dbd278965271252704eddb97b4384bf58b971054d517decfbf8c523f05"},
+    {file = "ruff-0.1.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5daaeaf00ae3c1efec9742ff294b06c3a2a9db8d3db51ee4851c12ad385cda30"},
+    {file = "ruff-0.1.8-py3-none-win32.whl", hash = "sha256:e49fbdfe257fa41e5c9e13c79b9e79a23a79bd0e40b9314bc53840f520c2c0b3"},
+    {file = "ruff-0.1.8-py3-none-win_amd64.whl", hash = "sha256:f41f692f1691ad87f51708b823af4bb2c5c87c9248ddd3191c8f088e66ce590a"},
+    {file = "ruff-0.1.8-py3-none-win_arm64.whl", hash = "sha256:aa8ee4f8440023b0a6c3707f76cadce8657553655dcbb5fc9b2f9bb9bee389f6"},
+    {file = "ruff-0.1.8.tar.gz", hash = "sha256:f7ee467677467526cfe135eab86a40a0e8db43117936ac4f9b469ce9cdb3fb62"},
 ]
 
 [[package]]
@@ -1861,19 +1956,19 @@ jeepney = ">=0.6"
 
 [[package]]
 name = "setuptools"
-version = "65.6.3"
+version = "69.0.2"
 description = "Easily download, build, install, upgrade, and uninstall Python packages"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
-    {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
+    {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"},
+    {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"},
 ]
 
 [package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
 
 [[package]]
 name = "six"
@@ -1888,36 +1983,32 @@ files = [
 
 [[package]]
 name = "snowflake-connector-python"
-version = "3.0.4"
+version = "3.6.0"
 description = "Snowflake Connector for Python"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "snowflake-connector-python-3.0.4.tar.gz", hash = "sha256:f0253a58909dcf57bcde4ce1ef613fe346fc18bc01ba20101d1499ac22f6d9b2"},
-    {file = "snowflake_connector_python-3.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75810c8964ff34e3fdced982c9bdf4b73335436585bcb538672f660ea14e74bd"},
-    {file = "snowflake_connector_python-3.0.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:dfdad463fe68c3372d9a80018452360d11dba455865613fd94850195fdd9c989"},
-    {file = "snowflake_connector_python-3.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:099dca938a52419be3ce4d332f7af2587f1316b2a63b109b2e1e18aac00e9ba9"},
-    {file = "snowflake_connector_python-3.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23f2f28702f59d04bd28eb27a0a87b5270b263f152ffa046b6ff058c09c0a945"},
-    {file = "snowflake_connector_python-3.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:48c3a1026ab83ab6205716fb9ecdf707534deb28b7891ea0708e57f8fef8472b"},
-    {file = "snowflake_connector_python-3.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c71f2db386de6cba165aa2b758aeae691f2319a9a280a1cd89937d87db89bf86"},
-    {file = "snowflake_connector_python-3.0.4-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:91e75ff12d47a0ec0015aec7c14f7d8bb2b0100a287c412ade11a78c5a1037b1"},
-    {file = "snowflake_connector_python-3.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcab2f51a143f9ea808dfeaa5bd72fc37149546f93bffa198132c333c4da8f00"},
-    {file = "snowflake_connector_python-3.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34646dde0ce84d03632734597577a4bf1aec5d6dee7edefb7aa71d6d6236a332"},
-    {file = "snowflake_connector_python-3.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:c61602bd9447988d24f95eafd0fc1d5af498e17e8669e81eef1b8699c1530120"},
-    {file = "snowflake_connector_python-3.0.4-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:834227edb0608d7544404fa35d857983a1ab373d0781a229c3572de6227cf5d5"},
-    {file = "snowflake_connector_python-3.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08b2041c6e33379cb4ec482b4e6ba3106580abc5c89f8647b6c99c203fb910ac"},
-    {file = "snowflake_connector_python-3.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b1c89cb4b6d04bcd2e7a378cae6ab9915bdd8bb0ef6dc4f27533b70c3eb3cb"},
-    {file = "snowflake_connector_python-3.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d994540b8eb68c25bea917ab6a933dd775939b4a4beec34b0b942400f959cd7a"},
-    {file = "snowflake_connector_python-3.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bb7b10842053b8f478baadbb7ea7160dc10c7f7085d69cb7a6e240afe231b078"},
-    {file = "snowflake_connector_python-3.0.4-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:61b6e04853029302d90d6ad3d3c189d1ed22f202c34e60fb3d33fb8957fb3661"},
-    {file = "snowflake_connector_python-3.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebaabef48dfe84fe4a705d42fd29c464c6d71ab1fc2b5606409672586ce6697f"},
-    {file = "snowflake_connector_python-3.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4514bd5ff67099af29b23a6c0a2c3e3634a023f4bba4324fd2a9763a61c448d"},
-    {file = "snowflake_connector_python-3.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:106efd608c243daac8f75067c716805aa5cc902d39538918edaf5661b622b4a1"},
-    {file = "snowflake_connector_python-3.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:acb0c2b825d6489feadd189bb16ad416da6df9bc39e5786a910e00cc19c3955a"},
-    {file = "snowflake_connector_python-3.0.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b68ce7fd755a43149caafe3f5738628606ee03557d3030881c9a5f08d1754c0f"},
-    {file = "snowflake_connector_python-3.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f7c79c0a3fb2c3490f46f23ac4ae1915c2a47e26c4b2df8b5d4116877c4c61"},
-    {file = "snowflake_connector_python-3.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17692755b8e79b1ad489b7e5966bb819c530c2239cb309c0b6c728fa135937f8"},
-    {file = "snowflake_connector_python-3.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:3af27737afdfc795b19066b6365e315fab314936b2ea71b486e8fd476834c249"},
+    {file = "snowflake-connector-python-3.6.0.tar.gz", hash = "sha256:15667a918780d79da755e6a60bbf6918051854951e8f56ccdf5692283e9a8479"},
+    {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4093b38cf9abf95c38119f0b23b07e23dc7a8689b956cd5d34975e1875741f20"},
+    {file = "snowflake_connector_python-3.6.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:cf5a964fe01b177063f8c44d14df3a72715580bcd195788ec2822090f37330a5"},
+    {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55a6418cec585b050e6f05404f25e62b075a3bbea587dc1f903de15640565c58"},
+    {file = "snowflake_connector_python-3.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7c76aea92b87f6ecd604e9c934aac8a779f2e20f3be1d990d53bb5b6d87b009"},
+    {file = "snowflake_connector_python-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:9dfcf178271e892e64e4092b9e011239a066ce5de848afd2efe3f13197a9f8b3"},
+    {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4916f9b4a0efd7c96d1fa50a157e05907b6935f91492cca7f200b43cc178a25e"},
+    {file = "snowflake_connector_python-3.6.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:f15024c66db5e87d359216ec733a2974d7562aa38f3f18c8b6e65489839e00d7"},
+    {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcbd3102f807ebbbae52b1b5683d45cd7b3dcb0eaec131233ba6b156e8d70fa4"},
+    {file = "snowflake_connector_python-3.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7662e2de25b885abe08ab866cf7c7b026ad1af9faa39c25e2c25015ef807abe3"},
+    {file = "snowflake_connector_python-3.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:d1fa102f55ee166cc766aeee3f9333b17b4bede6fb088eee1e1f022df15b6d81"},
+    {file = "snowflake_connector_python-3.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fde1e0727e2f23c2a07b49b30e1bc0f49977f965d08ddfda10015b24a2beeb76"},
+    {file = "snowflake_connector_python-3.6.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:1b51fe000c8cf6372d30b73c7136275e52788e6af47010cd1984c9fb03378e86"},
+    {file = "snowflake_connector_python-3.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7a11699689a19916e65794ce58dca72b8a40fe6a7eea06764931ede10b47bcc"},
+    {file = "snowflake_connector_python-3.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d810be5b180c6f47ce9b6f989fe64b9984383e4b77e30b284a83e33f229a3a82"},
+    {file = "snowflake_connector_python-3.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5db47d4164d6b7a07c413a46f9edc4a1d687e3df44fd9d5fa89a89aecb94a8e"},
+    {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bf8c1ad5aab5304fefa2a4178061a24c96da45e3e3db9d901621e9953e005402"},
+    {file = "snowflake_connector_python-3.6.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1058ab5c98cc62fde8b3f021f0a5076cb7865b5cdab8a9bccde0df88b9e91334"},
+    {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b93f55989f80d69278e0f40a7a1c0e737806b7c0ddb0351513a752b837243e8"},
+    {file = "snowflake_connector_python-3.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50dd954ea5918d3242ded69225b72f701963cd9c043ee7d9ab35dc22211611c8"},
+    {file = "snowflake_connector_python-3.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4ad42613b87f31441d07a8ea242f4c28ed5eb7b6e05986f9e94a7e44b96d3d1e"},
 ]
 
 [package.dependencies]
@@ -1925,24 +2016,24 @@ asn1crypto = ">0.24.0,<2.0.0"
 certifi = ">=2017.4.17"
 cffi = ">=1.9,<2.0.0"
 charset-normalizer = ">=2,<4"
-cryptography = ">=3.1.0,<41.0.0"
+cryptography = ">=3.1.0,<42.0.0"
 filelock = ">=3.5,<4"
 idna = ">=2.5,<4"
-oscrypto = "<2.0.0"
 packaging = "*"
-pycryptodomex = ">=3.2,<3.5.0 || >3.5.0,<4.0.0"
+platformdirs = ">=2.6.0,<4.0.0"
 pyjwt = "<3.0.0"
 pyOpenSSL = ">=16.2.0,<24.0.0"
 pytz = "*"
 requests = "<3.0.0"
 sortedcontainers = ">=2.4.0"
+tomlkit = "*"
 typing-extensions = ">=4.3,<5"
-urllib3 = ">=1.21.1,<1.27"
+urllib3 = {version = ">=1.21.1,<2.0.0", markers = "python_version < \"3.10\""}
 
 [package.extras]
-development = ["Cython", "coverage", "more-itertools", "numpy (<1.25.0)", "pendulum (!=2.1.1)", "pexpect", "pytest (<7.4.0)", "pytest-cov", "pytest-rerunfailures", "pytest-timeout", "pytest-xdist", "pytzdata"]
-pandas = ["pandas (>=1.0.0,<2.1.0)", "pyarrow (>=10.0.1,<10.1.0)"]
-secure-local-storage = ["keyring (!=16.1.0,<24.0.0)"]
+development = ["Cython", "coverage", "more-itertools", "numpy (<1.27.0)", "pendulum (!=2.1.1)", "pexpect", "pytest (<7.5.0)", "pytest-cov", "pytest-rerunfailures", "pytest-timeout", "pytest-xdist", "pytzdata"]
+pandas = ["pandas (>=1.0.0,<2.2.0)", "pyarrow"]
+secure-local-storage = ["keyring (!=16.1.0,<25.0.0)"]
 
 [[package]]
 name = "sortedcontainers"
@@ -1957,15 +2048,20 @@ files = [
 
 [[package]]
 name = "sqlparse"
-version = "0.4.3"
+version = "0.4.4"
 description = "A non-validating SQL parser."
 optional = false
 python-versions = ">=3.5"
 files = [
-    {file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"},
-    {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"},
+    {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"},
+    {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"},
 ]
 
+[package.extras]
+dev = ["build", "flake8"]
+doc = ["sphinx"]
+test = ["pytest", "pytest-cov"]
+
 [[package]]
 name = "tabulate"
 version = "0.9.0"
@@ -2002,6 +2098,17 @@ files = [
     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
 ]
 
+[[package]]
+name = "tomlkit"
+version = "0.12.3"
+description = "Style preserving TOML library"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"},
+    {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"},
+]
+
 [[package]]
 name = "trino"
 version = "0.314.0"
@@ -2024,57 +2131,66 @@ kerberos = ["requests-kerberos"]
 sqlalchemy = ["sqlalchemy (>=1.3,<2.0)"]
 tests = ["click", "httpretty (<1.1)", "pytest", "pytest-runner", "requests-kerberos", "sqlalchemy (>=1.3,<2.0)"]
 
+[[package]]
+name = "types-python-dateutil"
+version = "2.8.19.14"
+description = "Typing stubs for python-dateutil"
+optional = false
+python-versions = "*"
+files = [
+    {file = "types-python-dateutil-2.8.19.14.tar.gz", hash = "sha256:1f4f10ac98bb8b16ade9dbee3518d9ace017821d94b057a425b069f834737f4b"},
+    {file = "types_python_dateutil-2.8.19.14-py3-none-any.whl", hash = "sha256:f977b8de27787639986b4e28963263fd0e5158942b3ecef91b9335c130cb1ce9"},
+]
+
 [[package]]
 name = "typing-extensions"
-version = "4.7.1"
-description = "Backported and Experimental Type Hints for Python 3.7+"
+version = "4.9.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
-    {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
+    {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
+    {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
 ]
 
 [[package]]
 name = "tzdata"
-version = "2022.7"
+version = "2023.3"
 description = "Provider of IANA time zone data"
 optional = false
 python-versions = ">=2"
 files = [
-    {file = "tzdata-2022.7-py2.py3-none-any.whl", hash = "sha256:2b88858b0e3120792a3c0635c23daf36a7d7eeeca657c323da299d2094402a0d"},
-    {file = "tzdata-2022.7.tar.gz", hash = "sha256:fe5f866eddd8b96e9fcba978f8e503c909b19ea7efda11e52e39494bad3a7bfa"},
+    {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"},
+    {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
 ]
 
 [[package]]
 name = "tzlocal"
-version = "4.2"
+version = "5.2"
 description = "tzinfo object for the local timezone"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8"
 files = [
-    {file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"},
-    {file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"},
+    {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
+    {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
 ]
 
 [package.dependencies]
 "backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""}
-pytz-deprecation-shim = "*"
 tzdata = {version = "*", markers = "platform_system == \"Windows\""}
 
 [package.extras]
-devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"]
-test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"]
+devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"]
 
 [[package]]
 name = "unittest-parallel"
-version = "1.5.3"
+version = "1.6.1"
 description = "Parallel unit test runner with coverage support"
 optional = false
 python-versions = "*"
 files = [
-    {file = "unittest-parallel-1.5.3.tar.gz", hash = "sha256:32182bb2230371d651e6fc9795ddf52c134eb36f5064dc339fdbb5984a639517"},
-    {file = "unittest_parallel-1.5.3-py3-none-any.whl", hash = "sha256:5670c9eca19450dedb493e9dad2ca4dcbbe12e04477d934ff6c92071d36bace7"},
+    {file = "unittest-parallel-1.6.1.tar.gz", hash = "sha256:bbd8aee80eab882cbf1a0acf397658bb2b9beaa4ccf68cf78376f6a1f3d3688f"},
+    {file = "unittest_parallel-1.6.1-py3-none-any.whl", hash = "sha256:e5a8885e3df0e275d1cea579e91386a3b423922946eca6b175ad1fd06c3ea2e1"},
 ]
 
 [package.dependencies]
@@ -2082,29 +2198,29 @@ coverage = ">=5.1"
 
 [[package]]
 name = "urllib3"
-version = "1.26.13"
+version = "1.26.18"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 files = [
-    {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
-    {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
+    {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"},
+    {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"},
 ]
 
 [package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
 secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
 socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 
 [[package]]
 name = "vertica-python"
-version = "1.3.2"
+version = "1.3.7"
 description = "Official native Python client for the Vertica database."
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "vertica-python-1.3.2.tar.gz", hash = "sha256:3664f0610c16cd5d606b8bbe5c0a50359b1e979d9383c07967bbd49d4990a02f"},
-    {file = "vertica_python-1.3.2-py3-none-any.whl", hash = "sha256:e0096e430c0f8249dae0e15c1dd0d28a4e7fcd5216e12643d48eadc8e1cb0540"},
+    {file = "vertica-python-1.3.7.tar.gz", hash = "sha256:2a5f0d0111d3cc466b87923ffd3c262132a9fa0e38964e43eef90a3ccda57452"},
+    {file = "vertica_python-1.3.7-py3-none-any.whl", hash = "sha256:e8d3ceaa2b7a61a861590c8b5d822d2d71afad9ff3399fc67ee9888c5565ff74"},
 ]
 
 [package.dependencies]
@@ -2113,19 +2229,19 @@ six = ">=1.10.0"
 
 [[package]]
 name = "virtualenv"
-version = "20.24.6"
+version = "20.25.0"
 description = "Virtual Python Environment builder"
 optional = false
 python-versions = ">=3.7"
 files = [
-    {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"},
-    {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"},
+    {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"},
+    {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"},
 ]
 
 [package.dependencies]
 distlib = ">=0.3.7,<1"
 filelock = ">=3.12.2,<4"
-platformdirs = ">=3.9.1,<4"
+platformdirs = ">=3.9.1,<5"
 
 [package.extras]
 docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
@@ -2133,29 +2249,29 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
 
 [[package]]
 name = "wcwidth"
-version = "0.2.5"
+version = "0.2.12"
 description = "Measures the displayed width of unicode strings in a terminal"
 optional = false
 python-versions = "*"
 files = [
-    {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
-    {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
+    {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"},
+    {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"},
 ]
 
 [[package]]
 name = "zipp"
-version = "3.11.0"
+version = "3.17.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
 optional = false
-python-versions = ">=3.7"
+python-versions = ">=3.8"
 files = [
-    {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"},
-    {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"},
+    {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"},
+    {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"},
 ]
 
 [package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
-testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
+testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
 
 [extras]
 clickhouse = ["clickhouse-driver"]
@@ -2174,4 +2290,4 @@ vertica = ["vertica-python"]
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8.0"
-content-hash = "b7f8880be9658fa523ff4737d1fdefd09d124ab09fac22fa9ec6a83454940c1d"
+content-hash = "54f5248145c8920e27de3e781bb01461b3f68bc6335d75d8793b19dffd5f4163"
diff --git a/pyproject.toml b/pyproject.toml
index 1b380ddee..edc3f0b81 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -56,10 +56,10 @@ psycopg2 = "*"
 snowflake-connector-python = ">=3.0.2,<4.0.0"
 cryptography = "*"
 trino = "^0.314.0"
-presto-python-client = "*"
+presto-python-client = "0.8.3"
 clickhouse-driver = "*"
 vertica-python = "*"
-duckdb = "^0.7.0"
+duckdb = "^0.9.0"
 dbt-core = "^1.0.0"
 ruff = "^0.1.4"
 # google-cloud-bigquery = "*"
diff --git a/tests/dbt_artifacts/jaffle_shop.duckdb b/tests/dbt_artifacts/jaffle_shop.duckdb
index 5c1ad7d97678c4ed204c75e5e76a7aa9ce99cc4c..b0899b5f32b35b8e12da6cb2236d98a05a7b6b6a 100644
GIT binary patch
diff --git a/tests/dbt_artifacts/motherduck/profiles.yml b/tests/dbt_artifacts/motherduck/profiles.yml
new file mode 100644
index 000000000..ab288edda
--- /dev/null
+++ b/tests/dbt_artifacts/motherduck/profiles.yml
@@ -0,0 +1,7 @@
+jaffle_shop:
+  target: dev_motherduck
+  outputs:
+    dev_motherduck:
+      type: duckdb
+      path: 'md:jaffle_shop?motherduck_token={{ env_var("MOTHERDUCK_TOKEN") }}'
+      schema: dev
diff --git a/tests/dbt_artifacts/profiles.yml b/tests/dbt_artifacts/profiles.yml
index 57ebb61db..5a4b08315 100644
--- a/tests/dbt_artifacts/profiles.yml
+++ b/tests/dbt_artifacts/profiles.yml
@@ -5,7 +5,3 @@ jaffle_shop:
       type: duckdb
       path: "./tests/dbt_artifacts/jaffle_shop.duckdb"
       schema: dev
-    different_dev:
-      type: duckdb
-      path: "./tests/dbt_artifacts/jaffle_shop.duckdb"
-      schema: "{{ env_var('some_env_var') }}"
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index 31af99ebb..c56765539 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -45,6 +45,24 @@ def test_integration_basic_dbt(self):
             # 1 with a diff
             assert diff_string.count("  Rows Added    Rows Removed") == 1
 
+    def test_integration_motherduck_dbt(self):
+        artifacts_path = os.getcwd() + "/tests/dbt_artifacts"
+        test_project_path = os.environ.get("DATA_DIFF_DBT_PROJ") or artifacts_path
+        test_profiles_path = os.environ.get("DATA_DIFF_DBT_PROJ") or artifacts_path + "/motherduck"
+        diff = run_datadiff_cli(
+            "--dbt", "--dbt-project-dir", test_project_path, "--dbt-profiles-dir", test_profiles_path
+        )
+
+        # assertions for the diff that exists in tests/dbt_artifacts/jaffle_shop.duckdb
+        if test_project_path == artifacts_path:
+            diff_string = b"".join(diff).decode("utf-8")
+            # 5 diffs were ran
+            assert diff_string.count("<>") == 5
+            # 4 with no diffs
+            assert diff_string.count("No row differences") == 4
+            # 1 with a diff
+            assert diff_string.count("  Rows Added    Rows Removed") == 1
+
     def test_integration_cloud_dbt(self):
         project_dir = os.environ.get("DATA_DIFF_DBT_PROJ")
         if project_dir is not None:

From e5f1d84e4ee28f68fbaf229cf913ba6184098bec Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 19 Dec 2023 10:51:13 -0700
Subject: [PATCH 29/99] v0.10.0

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index 90ebae8a6..61fb31cae 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.10.0rc0"
+__version__ = "0.10.0"
diff --git a/pyproject.toml b/pyproject.toml
index edc3f0b81..3a2f07a6a 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.10.0rc0"
+version = "0.10.0"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From bf8c0132aefb4935708290642d8e345a7ba826a5 Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Thu, 21 Dec 2023 09:24:43 +1300
Subject: [PATCH 30/99] add vhol callout (#808)

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index fb422a472..4f386429e 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,8 @@ data-diff: Compare datasets fast, within or across SQL databases
 </h2>
 <br>
 
+> [Make sure to join us at our virtual hands-on lab series where our team walks through live how to get set-up with it!](https://www.datafold.com/virtual-hands-on-lab)
+
 # Use Cases
 
 ## Data Migration & Replication Testing

From 1c2350b2efab89e28ee3cb6f0b517ad1671d7fef Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Fri, 22 Dec 2023 07:56:25 +1300
Subject: [PATCH 31/99] Better Action Next Step when using CLI (#809)

* add vhol callout

* remove vs code language

* improve guidance

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
---
 README.md        |  2 --
 data_diff/dbt.py | 12 ++++++++----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index 4f386429e..1a0f1ba99 100644
--- a/README.md
+++ b/README.md
@@ -45,8 +45,6 @@ Test SQL code and preview changes by comparing development/staging environment d
 
 **[Get started with data-diff & dbt](https://docs.datafold.com/development_testing/open_source)**
 
-Also available in a [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=Datafold.datafold-vscode)
-
 Reach out on the dbt Slack in [#tools-datafold](https://getdbt.slack.com/archives/C03D25A92UU) for advice and support
 
 
diff --git a/data_diff/dbt.py b/data_diff/dbt.py
index ef7804292..92a1fdbe2 100644
--- a/data_diff/dbt.py
+++ b/data_diff/dbt.py
@@ -8,6 +8,7 @@
 import pydantic
 import rich
 from rich.prompt import Prompt
+from rich.markdown import Markdown
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 from data_diff.errors import (
@@ -50,7 +51,8 @@
 
 logger = getLogger(__name__)
 CLOUD_DOC_URL = "https://docs.datafold.com/development_testing/cloud"
-EXTENSION_INSTALL_URL = "https://get.datafold.com/datafold-vs-code-install"
+DATAFOLD_TRIAL_URL = "https://app.datafold.com/org-signup"
+DATAFOLD_INSTRUCTIONS_URL = "https://docs.datafold.com/development_testing/datafold_cloud"
 
 
 class TDiffVars(pydantic.BaseModel):
@@ -558,6 +560,8 @@ def _email_signup() -> None:
 
 def _extension_notification() -> None:
     if bool_notify_about_extension():
-        rich.print(
-            f"\n\nHaving a good time diffing? :heart_eyes-emoji:\nMake sure to check out the free [bold]Datafold VS Code extension[/bold] for more a more seamless diff experience:\n{EXTENSION_INSTALL_URL}"
-        )
+        message = "\n\nHaving a good time diffing?\n\nMake sure to check out the free Datafold Cloud Trial for an evolved experience:\n\n- value-level diffs\n- column-level lineage\n"
+        rich.print(message)
+        rich.print(Markdown(f"[Sign Up Here]({DATAFOLD_TRIAL_URL})"))
+        rich.print("")
+        rich.print(Markdown(f"[Follow the instructions to get started]({DATAFOLD_INSTRUCTIONS_URL})"))

From db7d8641d19a4417a378030671ce587035f5131e Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Thu, 21 Dec 2023 12:11:47 -0700
Subject: [PATCH 32/99] v0.10.1

---
 data_diff/version.py | 2 +-
 pyproject.toml       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index 61fb31cae..1f4c4d43b 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.10.0"
+__version__ = "0.10.1"
diff --git a/pyproject.toml b/pyproject.toml
index 3a2f07a6a..0fe15b4c2 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.10.0"
+version = "0.10.1"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"

From 2281af0d52f35d27fd942667baef98d3b4c83c2f Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sung@datafold.com>
Date: Wed, 27 Dec 2023 11:07:51 -0800
Subject: [PATCH 33/99] test this new action

---
 .github/workflows/formatter.yml | 13 ++++++++++++-
 data_diff/databases/mysql.py    | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/formatter.yml b/.github/workflows/formatter.yml
index 52ee99193..c1860fdf7 100644
--- a/.github/workflows/formatter.yml
+++ b/.github/workflows/formatter.yml
@@ -10,12 +10,23 @@ jobs:
     name: runner / ruff
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - name: Checkout PR head
+        uses: actions/checkout@v3
+        if: github.event_name == 'pull_request'
+        with:
+          repository: ${{ github.event.pull_request.head.repo.full_name }}
+          ref: ${{ github.event.pull_request.head.ref }}
+
+      - name: Checkout Repo 
+        uses: actions/checkout@v3
+        if: github.event_name == 'workflow_dispatch'
+
       - name: Check files using the ruff formatter
         uses: chartboost/ruff-action@v1
         id: ruff_formatter
         with:
           args: format
+
       - name: Auto commit ruff formatting
         uses: stefanzweifel/git-auto-commit-action@v5
         with:
diff --git a/data_diff/databases/mysql.py b/data_diff/databases/mysql.py
index 647388f26..401bbc855 100644
--- a/data_diff/databases/mysql.py
+++ b/data_diff/databases/mysql.py
@@ -1,4 +1,4 @@
-from typing import Any, ClassVar, Dict, Type
+from typing import Any, ClassVar, Dict, Type, Union
 
 import attrs
 
@@ -20,6 +20,7 @@
     import_helper,
     ConnectError,
     BaseDialect,
+    ThreadLocalInterpreter,
 )
 from data_diff.databases.base import (
     MD5_HEXDIGITS,
@@ -148,3 +149,14 @@ def create_connection(self):
             elif e.errno == mysql.errorcode.ER_BAD_DB_ERROR:
                 raise ConnectError("Database does not exist") from e
             raise ConnectError(*e.args) from e
+
+    def _query_in_worker(self, sql_code: Union[str, ThreadLocalInterpreter]):
+        "This method runs in a worker thread"
+        if self._init_error:
+            raise self._init_error
+        if not self.thread_local.conn.is_connected():
+            try:
+                self.thread_local.conn.ping(reconnect=True, attempts=3, delay=5)
+            except Exception as e:
+                raise ConnectError(*e.args) from e
+        return self._query_conn(self.thread_local.conn, sql_code)

From 280b7c5304bb9a12ae4dbb914415f17a0e7bd83f Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sung@datafold.com>
Date: Wed, 27 Dec 2023 11:13:22 -0800
Subject: [PATCH 34/99] revert

---
 data_diff/databases/mysql.py | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/data_diff/databases/mysql.py b/data_diff/databases/mysql.py
index 401bbc855..647388f26 100644
--- a/data_diff/databases/mysql.py
+++ b/data_diff/databases/mysql.py
@@ -1,4 +1,4 @@
-from typing import Any, ClassVar, Dict, Type, Union
+from typing import Any, ClassVar, Dict, Type
 
 import attrs
 
@@ -20,7 +20,6 @@
     import_helper,
     ConnectError,
     BaseDialect,
-    ThreadLocalInterpreter,
 )
 from data_diff.databases.base import (
     MD5_HEXDIGITS,
@@ -149,14 +148,3 @@ def create_connection(self):
             elif e.errno == mysql.errorcode.ER_BAD_DB_ERROR:
                 raise ConnectError("Database does not exist") from e
             raise ConnectError(*e.args) from e
-
-    def _query_in_worker(self, sql_code: Union[str, ThreadLocalInterpreter]):
-        "This method runs in a worker thread"
-        if self._init_error:
-            raise self._init_error
-        if not self.thread_local.conn.is_connected():
-            try:
-                self.thread_local.conn.ping(reconnect=True, attempts=3, delay=5)
-            except Exception as e:
-                raise ConnectError(*e.args) from e
-        return self._query_conn(self.thread_local.conn, sql_code)

From d5d227fb4bec43ee5e24e1e79badd04047e12528 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 20 Dec 2023 11:13:28 +0100
Subject: [PATCH 35/99] Ignore columns at runtime on request (e.g. with too
 many diffs in them)

---
 data_diff/diff_tables.py     | 34 ++++++++++++++++++++--
 data_diff/hashdiff_tables.py | 56 +++++++++++++++++++++++++++---------
 data_diff/table_segment.py   | 18 +++++++-----
 3 files changed, 85 insertions(+), 23 deletions(-)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 668024264..518cc1227 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -1,12 +1,12 @@
 """Provides classes for performing a table diff
 """
-
+import threading
 import time
 from abc import ABC, abstractmethod
 from enum import Enum
 from contextlib import contextmanager
 from operator import methodcaller
-from typing import Dict, Tuple, Iterator, Optional
+from typing import Dict, Set, Tuple, Iterator, Optional
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 import attrs
@@ -184,6 +184,10 @@ class TableDiffer(ThreadBase, ABC):
     bisection_factor = 32
     stats: dict = {}
 
+    ignored_columns1: Set[str] = attrs.field(factory=set)
+    ignored_columns2: Set[str] = attrs.field(factory=set)
+    _ignored_columns_lock: threading.Lock = attrs.field(factory=threading.Lock, init=False)
+
     def diff_tables(self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree = None) -> DiffResultWrapper:
         """Diff the given tables.
 
@@ -353,6 +357,11 @@ def _bisect_and_diff_segments(
         biggest_table = max(table1, table2, key=methodcaller("approximate_size"))
         checkpoints = biggest_table.choose_checkpoints(self.bisection_factor - 1)
 
+        # Get it thread-safe, to avoid segment misalignment because of bad timing.
+        with self._ignored_columns_lock:
+            table1 = attrs.evolve(table1, ignored_columns=frozenset(self.ignored_columns1))
+            table2 = attrs.evolve(table2, ignored_columns=frozenset(self.ignored_columns2))
+
         # Create new instances of TableSegment between each checkpoint
         segmented1 = table1.segment_by_checkpoints(checkpoints)
         segmented2 = table2.segment_by_checkpoints(checkpoints)
@@ -363,3 +372,24 @@ def _bisect_and_diff_segments(
             ti.submit(
                 self._diff_segments, ti, t1, t2, info_node, max_rows, level + 1, i + 1, len(segmented1), priority=level
             )
+
+    def ignore_column(self, column_name1: str, column_name2: str) -> None:
+        """
+        Ignore the column (by name on sides A & B) in md5s & diffs from now on.
+
+        This affects 2 places:
+
+        - The columns are not checksumed for new(!) segments.
+        - The columns are ignored in in-memory diffing for running segments.
+
+        The columns are never ignored in the fetched values, whether they are
+        the same or different — for data consistency.
+
+        Use this feature to collect relatively well-represented differences
+        across all columns if one of them is highly different in the beginning
+        of a table (as per the order of segmentation/bisection). Otherwise,
+        that one column might easily hit the limit and stop the whole diff.
+        """
+        with self._ignored_columns_lock:
+            self.ignored_columns1.add(column_name1)
+            self.ignored_columns2.add(column_name2)
diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 1b2ec84fb..82f33369d 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -2,9 +2,10 @@
 from numbers import Number
 import logging
 from collections import defaultdict
-from typing import Iterator
+from typing import Any, Collection, Dict, Iterator, List, Sequence, Set, Tuple
 
 import attrs
+from typing_extensions import Literal
 
 from data_diff.abcs.database_types import ColType_UUID, NumericType, PrecisionType, StringType, Boolean, JSON
 from data_diff.info_tree import InfoTree
@@ -20,25 +21,42 @@
 
 logger = logging.getLogger("hashdiff_tables")
 
-
-def diff_sets(a: list, b: list, json_cols: dict = None) -> Iterator:
-    sa = set(a)
-    sb = set(b)
+# Just for local readability: TODO: later switch to real type declarations of these.
+_Op = Literal["+", "-"]
+_PK = Any
+_Row = Tuple[Any]
+
+
+def diff_sets(
+    a: Sequence[_Row],
+    b: Sequence[_Row],
+    *,
+    json_cols: dict = None,
+    columns1: Sequence[str],
+    columns2: Sequence[str],
+    ignored_columns1: Collection[str],
+    ignored_columns2: Collection[str],
+) -> Iterator:
+    # Differ only by columns of interest (PKs+relevant-ignored). But yield with ignored ones!
+    sa: Set[_Row] = {tuple(val for col, val in safezip(columns1, row) if col not in ignored_columns1) for row in a}
+    sb: Set[_Row] = {tuple(val for col, val in safezip(columns2, row) if col not in ignored_columns2) for row in b}
 
     # The first item is always the key (see TableDiffer.relevant_columns)
     # TODO update when we add compound keys to hashdiff
-    d = defaultdict(list)
+    diffs_by_pks: Dict[_PK, List[Tuple[_Op, _Row]]] = defaultdict(list)
     for row in a:
-        if row not in sb:
-            d[row[0]].append(("-", row))
+        cutrow: _Row = tuple(val for col, val in zip(columns1, row) if col not in ignored_columns1)
+        if cutrow not in sb:
+            diffs_by_pks[row[0]].append(("-", row))
     for row in b:
-        if row not in sa:
-            d[row[0]].append(("+", row))
+        cutrow: _Row = tuple(val for col, val in zip(columns2, row) if col not in ignored_columns2)
+        if cutrow not in sa:
+            diffs_by_pks[row[0]].append(("+", row))
 
     warned_diff_cols = set()
-    for _k, v in sorted(d.items(), key=lambda i: i[0]):
+    for diffs in (diffs_by_pks[pk] for pk in sorted(diffs_by_pks)):
         if json_cols:
-            parsed_match, overriden_diff_cols = diffs_are_equiv_jsons(v, json_cols)
+            parsed_match, overriden_diff_cols = diffs_are_equiv_jsons(diffs, json_cols)
             if parsed_match:
                 to_warn = overriden_diff_cols - warned_diff_cols
                 for w in to_warn:
@@ -48,7 +66,7 @@ def diff_sets(a: list, b: list, json_cols: dict = None) -> Iterator:
                     )
                     warned_diff_cols.add(w)
                 continue
-        yield from v
+        yield from diffs
 
 
 @attrs.define(frozen=False)
@@ -201,7 +219,17 @@ def _bisect_and_diff_segments(
                 for i, colname in enumerate(table1.extra_columns)
                 if isinstance(table1._schema[colname], JSON)
             }
-            diff = list(diff_sets(rows1, rows2, json_cols))
+            diff = list(
+                diff_sets(
+                    rows1,
+                    rows2,
+                    json_cols=json_cols,
+                    columns1=table1.relevant_columns,
+                    columns2=table2.relevant_columns,
+                    ignored_columns1=self.ignored_columns1,
+                    ignored_columns2=self.ignored_columns1,
+                )
+            )
 
             info_tree.info.set_diff(diff)
             info_tree.info.rowcounts = {1: len(rows1), 2: len(rows2)}
diff --git a/data_diff/table_segment.py b/data_diff/table_segment.py
index d8f842313..2cf81a708 100644
--- a/data_diff/table_segment.py
+++ b/data_diff/table_segment.py
@@ -1,5 +1,5 @@
 import time
-from typing import List, Optional, Tuple
+from typing import Container, List, Optional, Tuple
 import logging
 from itertools import product
 
@@ -114,6 +114,7 @@ class TableSegment:
     key_columns: Tuple[str, ...]
     update_column: Optional[str] = None
     extra_columns: Tuple[str, ...] = ()
+    ignored_columns: Container[str] = frozenset()
 
     # Restrict the segment
     min_key: Optional[Vector] = None
@@ -179,7 +180,10 @@ def make_select(self):
 
     def get_values(self) -> list:
         "Download all the relevant values of the segment from the database"
-        select = self.make_select().select(*self._relevant_columns_repr)
+
+        # Fetch all the original columns, even if some were later excluded from checking.
+        fetched_cols = [NormalizeAsString(this[c]) for c in self.relevant_columns]
+        select = self.make_select().select(*fetched_cols)
         return self.database.query(select, List[Tuple])
 
     def choose_checkpoints(self, count: int) -> List[List[DbKey]]:
@@ -221,18 +225,18 @@ def relevant_columns(self) -> List[str]:
 
         return list(self.key_columns) + extras
 
-    @property
-    def _relevant_columns_repr(self) -> List[Expr]:
-        return [NormalizeAsString(this[c]) for c in self.relevant_columns]
-
     def count(self) -> int:
         """Count how many rows are in the segment, in one pass."""
         return self.database.query(self.make_select().select(Count()), int)
 
     def count_and_checksum(self) -> Tuple[int, int]:
         """Count and checksum the rows in the segment, in one pass."""
+
+        checked_columns = [c for c in self.relevant_columns if c not in self.ignored_columns]
+        cols = [NormalizeAsString(this[c]) for c in checked_columns]
+
         start = time.monotonic()
-        q = self.make_select().select(Count(), Checksum(self._relevant_columns_repr))
+        q = self.make_select().select(Count(), Checksum(cols))
         count, checksum = self.database.query(q, tuple)
         duration = time.monotonic() - start
         if duration > RECOMMENDED_CHECKSUM_DURATION:

From c13e21b45452fcf3bde2db83f36b04b1f124c6dc Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 12:12:44 +0100
Subject: [PATCH 36/99] add tests for checking precision

---
 data_diff/databases/base.py       |  1 +
 data_diff/databases/bigquery.py   |  3 +++
 data_diff/databases/duckdb.py     |  4 ++++
 data_diff/databases/postgresql.py |  6 ++++++
 tests/test_database.py            | 33 +++++++++++++++++++++++++++++++
 5 files changed, 47 insertions(+)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 059854a5f..6d1fdb912 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -201,6 +201,7 @@ class BaseDialect(abc.ABC):
     SUPPORTS_INDEXES: ClassVar[bool] = False
     PREVENT_OVERFLOW_WHEN_CONCAT: ClassVar[bool] = False
     TYPE_CLASSES: ClassVar[Dict[str, Type[ColType]]] = {}
+    DEFAULT_NUMERIC_PRECISION: ClassVar[int] = 0  # effective precision when type is just "NUMERIC"
 
     PLACEHOLDER_TABLE = None  # Used for Oracle
 
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 26d8aec3d..b4eefe0cd 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -75,6 +75,9 @@ class Dialect(BaseDialect):
     }
     TYPE_ARRAY_RE = re.compile(r"ARRAY<(.+)>")
     TYPE_STRUCT_RE = re.compile(r"STRUCT<(.+)>")
+    # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#parameterized_decimal_type
+    # The default scale is 9, which means a number can have up to 9 digits after the decimal point.
+    DEFAULT_NUMERIC_PRECISION = 9
 
     def random(self) -> str:
         return "RAND()"
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index d057e0d90..e6f3fb9dd 100644
--- a/data_diff/databases/duckdb.py
+++ b/data_diff/databases/duckdb.py
@@ -45,6 +45,10 @@ class Dialect(BaseDialect):
     SUPPORTS_PRIMARY_KEY = True
     SUPPORTS_INDEXES = True
 
+    # https://duckdb.org/docs/sql/data_types/numeric#fixed-point-decimals
+    # The default WIDTH and SCALE is DECIMAL(18, 3), if none are specified.
+    DEFAULT_NUMERIC_PRECISION = 3
+
     TYPE_CLASSES = {
         # Timestamps
         "TIMESTAMP WITH TIME ZONE": TimestampTZ,
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index d29fa0eb5..b3203e317 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -45,6 +45,12 @@ class PostgresqlDialect(BaseDialect):
     SUPPORTS_PRIMARY_KEY: ClassVar[bool] = True
     SUPPORTS_INDEXES = True
 
+    # https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NUMERIC-DECIMAL
+    # without any precision or scale creates an “unconstrained numeric” column
+    # in which numeric values of any length can be stored, up to the implementation limits.
+    # https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-NUMERIC-TABLE
+    DEFAULT_NUMERIC_PRECISION = 16383
+
     TYPE_CLASSES: ClassVar[Dict[str, Type[ColType]]] = {
         # Timestamps
         "timestamp with time zone": TimestampTZ,
diff --git a/tests/test_database.py b/tests/test_database.py
index 0280eae1c..98eec37e1 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -134,3 +134,36 @@ def test_three_part_support(self):
             d = db.query_table_schema(part.path)
             assert len(d) == 1
             db.query(part.drop())
+
+
+@test_each_database
+class TestNumericPrecisionParsing(unittest.TestCase):
+    def test_specified_precision(self):
+        name = "tbl_" + random_table_suffix()
+        db = get_conn(self.db_cls)
+        tbl = table(name, schema={"value": "NUMERIC(10, 2)"})
+        db.query(tbl.create())
+        t = table(name)
+        raw_schema = db.query_table_schema(t.path)
+        schema = db._process_table_schema(t.path, raw_schema)
+        self.assertEqual(schema["value"].precision,  2)
+
+    def test_specified_zero_precision(self):
+        name = "tbl_" + random_table_suffix()
+        db = get_conn(self.db_cls)
+        tbl = table(name, schema={"value": "NUMERIC(10)"})
+        db.query(tbl.create())
+        t = table(name)
+        raw_schema = db.query_table_schema(t.path)
+        schema = db._process_table_schema(t.path, raw_schema)
+        self.assertEqual(schema["value"].precision, 0)
+
+    def test_default_precision(self):
+        name = "tbl_" + random_table_suffix()
+        db = get_conn(self.db_cls)
+        tbl = table(name, schema={"value": "NUMERIC"})
+        db.query(tbl.create())
+        t = table(name)
+        raw_schema = db.query_table_schema(t.path)
+        schema = db._process_table_schema(t.path, raw_schema)
+        self.assertEqual(schema["value"].precision, db.dialect.DEFAULT_NUMERIC_PRECISION)

From 6a18838227ee33bfc51d479090867635d31338d8 Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 13:16:56 +0100
Subject: [PATCH 37/99] fix precision fetching for pg

---
 data_diff/databases/postgresql.py | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index b3203e317..34863ca44 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -191,8 +191,21 @@ def select_table_schema(self, path: DbPath) -> str:
             info_schema_path.insert(0, database)
 
         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"""
+            SELECT column_name, data_type, datetime_precision,
+                CASE
+                    WHEN data_type = 'numeric'
+                        THEN coalesce(numeric_precision, 131072 + 16383)
+                    ELSE numeric_precision
+                END AS numeric_precision,
+                CASE
+                    WHEN data_type = 'numeric'
+                        THEN coalesce(numeric_scale, 16383)
+                    ELSE numeric_scale
+                END AS numeric_scale
+                FROM {'.'.join(info_schema_path)}
+            WHERE table_name = '{table}' AND table_schema = '{schema}'
+            """
         )
 
     def select_table_unique_columns(self, path: DbPath) -> str:

From 3ce1832eccf7bdb8dffd05157243af0c6e3ec8b5 Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 13:21:51 +0100
Subject: [PATCH 38/99] =?UTF-8?q?NUMERIC=20=E2=86=92=20DECIMAL?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 tests/test_database.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/test_database.py b/tests/test_database.py
index 98eec37e1..f50d06817 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -141,7 +141,7 @@ class TestNumericPrecisionParsing(unittest.TestCase):
     def test_specified_precision(self):
         name = "tbl_" + random_table_suffix()
         db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "NUMERIC(10, 2)"})
+        tbl = table(name, schema={"value": "DECIMAL(10, 2)"})
         db.query(tbl.create())
         t = table(name)
         raw_schema = db.query_table_schema(t.path)
@@ -151,7 +151,7 @@ def test_specified_precision(self):
     def test_specified_zero_precision(self):
         name = "tbl_" + random_table_suffix()
         db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "NUMERIC(10)"})
+        tbl = table(name, schema={"value": "DECIMAL(10)"})
         db.query(tbl.create())
         t = table(name)
         raw_schema = db.query_table_schema(t.path)
@@ -161,7 +161,7 @@ def test_specified_zero_precision(self):
     def test_default_precision(self):
         name = "tbl_" + random_table_suffix()
         db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "NUMERIC"})
+        tbl = table(name, schema={"value": "DECIMAL"})
         db.query(tbl.create())
         t = table(name)
         raw_schema = db.query_table_schema(t.path)

From b2ce7548e83cf0d5f55e9d5c0847383e65633a9f Mon Sep 17 00:00:00 2001
From: vvkh <vvkh@users.noreply.github.com>
Date: Fri, 29 Dec 2023 12:22:33 +0000
Subject: [PATCH 39/99] style fixes by ruff

---
 data_diff/databases/postgresql.py | 4 +---
 tests/test_database.py            | 2 +-
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 34863ca44..69a328476 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -190,8 +190,7 @@ def select_table_schema(self, path: DbPath) -> str:
         if database:
             info_schema_path.insert(0, database)
 
-        return (
-            f"""
+        return f"""
             SELECT column_name, data_type, datetime_precision,
                 CASE
                     WHEN data_type = 'numeric'
@@ -206,7 +205,6 @@ def select_table_schema(self, path: DbPath) -> str:
                 FROM {'.'.join(info_schema_path)}
             WHERE table_name = '{table}' AND table_schema = '{schema}'
             """
-        )
 
     def select_table_unique_columns(self, path: DbPath) -> str:
         database, schema, table = self._normalize_table_path(path)
diff --git a/tests/test_database.py b/tests/test_database.py
index f50d06817..2713ac16d 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -146,7 +146,7 @@ def test_specified_precision(self):
         t = table(name)
         raw_schema = db.query_table_schema(t.path)
         schema = db._process_table_schema(t.path, raw_schema)
-        self.assertEqual(schema["value"].precision,  2)
+        self.assertEqual(schema["value"].precision, 2)
 
     def test_specified_zero_precision(self):
         name = "tbl_" + random_table_suffix()

From da1af645e2ca9637433248851d41c9413aa37786 Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 13:26:22 +0100
Subject: [PATCH 40/99] fix precision parsing for big query

---
 data_diff/databases/bigquery.py | 43 ++++++++++++++++++++++-----------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index b4eefe0cd..e819fe6d1 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -75,6 +75,8 @@ class Dialect(BaseDialect):
     }
     TYPE_ARRAY_RE = re.compile(r"ARRAY<(.+)>")
     TYPE_STRUCT_RE = re.compile(r"STRUCT<(.+)>")
+    # [BIG]NUMERIC, [BIG]NUMERIC(precision, scale), [BIG]NUMERIC(precision)
+    TYPE_NUMERIC_RE = re.compile(r'^((BIG)?NUMERIC)(?:\((\d+)(?:, (\d+))?\))?$')
     # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#parameterized_decimal_type
     # The default scale is 9, which means a number can have up to 9 digits after the decimal point.
     DEFAULT_NUMERIC_PRECISION = 9
@@ -103,20 +105,33 @@ def parse_type(
         **kwargs: Any,  # pass-through args
     ) -> ColType:
         col_type = super().parse_type(table_path, col_name, type_repr, *args, **kwargs)
-        if isinstance(col_type, UnknownColType):
-            m = self.TYPE_ARRAY_RE.fullmatch(type_repr)
-            if m:
-                item_type = self.parse_type(table_path, col_name, m.group(1), *args, **kwargs)
-                col_type = Array(item_type=item_type)
-
-            # We currently ignore structs' structure, but later can parse it too. Examples:
-            # - STRUCT<INT64, STRING(10)> (unnamed)
-            # - STRUCT<foo INT64, bar STRING(10)> (named)
-            # - STRUCT<foo INT64, bar ARRAY<INT64>> (with complex fields)
-            # - STRUCT<foo INT64, bar STRUCT<a INT64, b INT64>> (nested)
-            m = self.TYPE_STRUCT_RE.fullmatch(type_repr)
-            if m:
-                col_type = Struct()
+        if not isinstance(col_type, UnknownColType):
+            return col_type
+
+        m = self.TYPE_ARRAY_RE.fullmatch(type_repr)
+        if m:
+            item_type = self.parse_type(table_path, col_name, m.group(1), *args, **kwargs)
+            col_type = Array(item_type=item_type)
+            return col_type
+
+        # We currently ignore structs' structure, but later can parse it too. Examples:
+        # - STRUCT<INT64, STRING(10)> (unnamed)
+        # - STRUCT<foo INT64, bar STRING(10)> (named)
+        # - STRUCT<foo INT64, bar ARRAY<INT64>> (with complex fields)
+        # - STRUCT<foo INT64, bar STRUCT<a INT64, b INT64>> (nested)
+        m = self.TYPE_STRUCT_RE.fullmatch(type_repr)
+        if m:
+            col_type = Struct()
+            return col_type
+
+        m = self.TYPE_NUMERIC_RE.fullmatch(type_repr)
+        if m:
+            precision = int(m.group(3)) if m.group(3) else None
+            scale = int(m.group(4)) if m.group(4) else None
+            col_type = Decimal(
+                precision=scale if scale else 0 if precision else 9
+            )
+            return col_type
 
         return col_type
 

From 8f091e848eefdc8627489b5c78d6a5d0c67ed21e Mon Sep 17 00:00:00 2001
From: vvkh <vvkh@users.noreply.github.com>
Date: Fri, 29 Dec 2023 12:27:55 +0000
Subject: [PATCH 41/99] style fixes by ruff

---
 data_diff/databases/bigquery.py | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index e819fe6d1..f0e985c0a 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -76,7 +76,7 @@ class Dialect(BaseDialect):
     TYPE_ARRAY_RE = re.compile(r"ARRAY<(.+)>")
     TYPE_STRUCT_RE = re.compile(r"STRUCT<(.+)>")
     # [BIG]NUMERIC, [BIG]NUMERIC(precision, scale), [BIG]NUMERIC(precision)
-    TYPE_NUMERIC_RE = re.compile(r'^((BIG)?NUMERIC)(?:\((\d+)(?:, (\d+))?\))?$')
+    TYPE_NUMERIC_RE = re.compile(r"^((BIG)?NUMERIC)(?:\((\d+)(?:, (\d+))?\))?$")
     # https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#parameterized_decimal_type
     # The default scale is 9, which means a number can have up to 9 digits after the decimal point.
     DEFAULT_NUMERIC_PRECISION = 9
@@ -128,9 +128,7 @@ def parse_type(
         if m:
             precision = int(m.group(3)) if m.group(3) else None
             scale = int(m.group(4)) if m.group(4) else None
-            col_type = Decimal(
-                precision=scale if scale else 0 if precision else 9
-            )
+            col_type = Decimal(precision=scale if scale else 0 if precision else 9)
             return col_type
 
         return col_type

From 781d2ead85d5831baad63f822a4ac1dd0d1b2e8f Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 13:33:37 +0100
Subject: [PATCH 42/99] fix failing pg tests

---
 data_diff/databases/postgresql.py | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 69a328476..5dcd319b4 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -190,21 +190,23 @@ def select_table_schema(self, path: DbPath) -> str:
         if database:
             info_schema_path.insert(0, database)
 
-        return f"""
-            SELECT column_name, data_type, datetime_precision,
-                CASE
-                    WHEN data_type = 'numeric'
-                        THEN coalesce(numeric_precision, 131072 + 16383)
-                    ELSE numeric_precision
-                END AS numeric_precision,
-                CASE
-                    WHEN data_type = 'numeric'
-                        THEN coalesce(numeric_scale, 16383)
-                    ELSE numeric_scale
-                END AS numeric_scale
-                FROM {'.'.join(info_schema_path)}
-            WHERE table_name = '{table}' AND table_schema = '{schema}'
+        return (
+            f"""SELECT column_name, data_type, datetime_precision,
+                    -- see comment for DEFAULT_NUMERIC_PRECISION
+                    CASE
+                        WHEN data_type = 'numeric'
+                            THEN coalesce(numeric_precision, 131072 + {self.dialect.DEFAULT_NUMERIC_PRECISION})
+                        ELSE numeric_precision
+                    END AS numeric_precision,
+                    CASE
+                        WHEN data_type = 'numeric'
+                            THEN coalesce(numeric_scale, {self.dialect.DEFAULT_NUMERIC_PRECISION})
+                        ELSE numeric_scale
+                    END AS numeric_scale
+                    FROM {'.'.join(info_schema_path)}
+                    WHERE table_name = '{table}' AND table_schema = '{schema}'
             """
+        )
 
     def select_table_unique_columns(self, path: DbPath) -> str:
         database, schema, table = self._normalize_table_path(path)

From 6f6b887ca2377b83c451ec53ba8f270f51dec6e9 Mon Sep 17 00:00:00 2001
From: vvkh <vvkh@users.noreply.github.com>
Date: Fri, 29 Dec 2023 12:35:41 +0000
Subject: [PATCH 43/99] style fixes by ruff

---
 data_diff/databases/postgresql.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 5dcd319b4..6c6c35ed5 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -190,8 +190,7 @@ def select_table_schema(self, path: DbPath) -> str:
         if database:
             info_schema_path.insert(0, database)
 
-        return (
-            f"""SELECT column_name, data_type, datetime_precision,
+        return f"""SELECT column_name, data_type, datetime_precision,
                     -- see comment for DEFAULT_NUMERIC_PRECISION
                     CASE
                         WHEN data_type = 'numeric'
@@ -206,7 +205,6 @@ def select_table_schema(self, path: DbPath) -> str:
                     FROM {'.'.join(info_schema_path)}
                     WHERE table_name = '{table}' AND table_schema = '{schema}'
             """
-        )
 
     def select_table_unique_columns(self, path: DbPath) -> str:
         database, schema, table = self._normalize_table_path(path)

From f126f4571bbd9e616a3a5e8496ea979d5aee8915 Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 29 Dec 2023 13:52:56 +0100
Subject: [PATCH 44/99] fix vertica tests

---
 data_diff/databases/vertica.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index 23f63accd..fa46a42eb 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -56,6 +56,9 @@ class Dialect(BaseDialect):
         "boolean": Boolean,
     }
 
+    # https://www.vertica.com/docs/9.3.x/HTML/Content/Authoring/SQLReferenceManual/DataTypes/Numeric/NUMERIC.htm#Default
+    DEFAULT_NUMERIC_PRECISION = 15
+
     def quote(self, s: str):
         return f'"{s}"'
 

From 60ac1699442388eea28b20c39a56f4b5d2169041 Mon Sep 17 00:00:00 2001
From: Hanmiao Li <hanmiao.li@clickzetta.com>
Date: Sat, 30 Dec 2023 03:55:25 +0800
Subject: [PATCH 45/99] [to#811]Fix special characters in PG url and Mysql
 connection reconnect (#812)

* [to#811]Fix special characters in PG

* add TestSpecialCharacterPassword UT for pg

* format import

* format fix

* quick nits

* add newline

* format changed files

---------

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>
---
 data_diff/databases/mysql.py      | 11 +++++++-
 data_diff/databases/postgresql.py |  3 ++-
 tests/test_postgresql.py          | 42 ++++++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/data_diff/databases/mysql.py b/data_diff/databases/mysql.py
index 647388f26..2b1e810fe 100644
--- a/data_diff/databases/mysql.py
+++ b/data_diff/databases/mysql.py
@@ -1,4 +1,4 @@
-from typing import Any, ClassVar, Dict, Type
+from typing import Any, ClassVar, Dict, Type, Union
 
 import attrs
 
@@ -20,6 +20,7 @@
     import_helper,
     ConnectError,
     BaseDialect,
+    ThreadLocalInterpreter,
 )
 from data_diff.databases.base import (
     MD5_HEXDIGITS,
@@ -148,3 +149,11 @@ def create_connection(self):
             elif e.errno == mysql.errorcode.ER_BAD_DB_ERROR:
                 raise ConnectError("Database does not exist") from e
             raise ConnectError(*e.args) from e
+
+    def _query_in_worker(self, sql_code: Union[str, ThreadLocalInterpreter]):
+        "This method runs in a worker thread"
+        if self._init_error:
+            raise self._init_error
+        if not self.thread_local.conn.is_connected():
+            self.thread_local.conn.ping(reconnect=True, attempts=3, delay=5)
+        return self._query_conn(self.thread_local.conn, sql_code)
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index d29fa0eb5..e9a38cde8 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -1,5 +1,5 @@
 from typing import Any, ClassVar, Dict, List, Type
-
+from urllib.parse import unquote
 import attrs
 
 from data_diff.abcs.database_types import (
@@ -168,6 +168,7 @@ def create_connection(self):
 
         pg = import_postgresql()
         try:
+            self._args["password"] = unquote(self._args["password"])
             self._conn = pg.connect(
                 **self._args, keepalives=1, keepalives_idle=5, keepalives_interval=2, keepalives_count=2
             )
diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py
index b5e9fa10f..ed1baecf1 100644
--- a/tests/test_postgresql.py
+++ b/tests/test_postgresql.py
@@ -1,9 +1,11 @@
 import unittest
 
+from urllib.parse import quote
 from data_diff.queries.api import table, commit
 from data_diff import TableSegment, HashDiffer
 from data_diff import databases as db
-from tests.common import get_conn, random_table_suffix
+from tests.common import get_conn, random_table_suffix, connect
+from data_diff import connect_to_table
 
 
 class TestUUID(unittest.TestCase):
@@ -113,3 +115,41 @@ def test_100_fields(self):
         id_ = diff[0][1][0]
         result = (id_,) + tuple("1" for x in range(100))
         self.assertEqual(diff, [("-", result)])
+
+
+class TestSpecialCharacterPassword(unittest.TestCase):
+    def setUp(self) -> None:
+        self.connection = get_conn(db.PostgreSQL)
+
+        table_suffix = random_table_suffix()
+
+        self.table_name = f"table{table_suffix}"
+        self.table = table(self.table_name)
+
+    def test_special_char_password(self):
+        password = "passw!!!@rd"
+        # Setup user with special character '@' in password
+        self.connection.query("DROP USER IF EXISTS test;", None)
+        self.connection.query(f"CREATE USER test WITH PASSWORD '{password}';", None)
+
+        password_quoted = quote(password)
+        db_config = {
+            "driver": "postgresql",
+            "host": "localhost",
+            "port": 5432,
+            "dbname": "postgres",
+            "user": "test",
+            "password": password_quoted,
+        }
+
+        # verify pythonic connection method
+        connect_to_table(
+            db_config,
+            self.table_name,
+        )
+
+        # verify connection method with URL string unquoted after it's verified
+        db_url = f"postgresql://{db_config['user']}:{db_config['password']}@{db_config['host']}:{db_config['port']}/{db_config['dbname']}"
+
+        connection_verified = connect(db_url)
+        assert connection_verified._args.get("password") == password

From 9f27117f4c98c43a61a7b4df4480f62e8d8dc909 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Mon, 18 Dec 2023 15:34:22 +0100
Subject: [PATCH 46/99] Group raw column info from rows to structures for
 schema parsing

---
 data_diff/__main__.py             |  6 ++--
 data_diff/databases/base.py       | 60 +++++++++++++++++--------------
 data_diff/databases/bigquery.py   | 19 ++++------
 data_diff/databases/clickhouse.py | 22 ++++++------
 data_diff/databases/databricks.py | 42 +++++++++++++---------
 data_diff/databases/duckdb.py     | 15 +++-----
 data_diff/databases/oracle.py     | 15 +++-----
 data_diff/databases/presto.py     | 19 ++++------
 data_diff/databases/redshift.py   | 40 ++++++++++++++-------
 data_diff/databases/vertica.py    | 19 ++++------
 data_diff/dbt.py                  |  2 +-
 data_diff/schema.py               | 32 +++++++++++++++++
 data_diff/table_segment.py        |  8 ++---
 tests/test_dbt.py                 | 21 ++++++++---
 14 files changed, 182 insertions(+), 138 deletions(-)

diff --git a/data_diff/__main__.py b/data_diff/__main__.py
index 06140ad1b..c4e698f5c 100644
--- a/data_diff/__main__.py
+++ b/data_diff/__main__.py
@@ -12,8 +12,8 @@
 from rich.logging import RichHandler
 import click
 
-from data_diff import Database
-from data_diff.schema import create_schema
+from data_diff import Database, DbPath
+from data_diff.schema import RawColumnInfo, create_schema
 from data_diff.queries.api import current_timestamp
 
 from data_diff.dbt import dbt_diff
@@ -72,7 +72,7 @@ def _remove_passwords_in_dict(d: dict) -> None:
             d[k] = remove_password_from_url(v)
 
 
-def _get_schema(pair):
+def _get_schema(pair: Tuple[Database, DbPath]) -> Dict[str, RawColumnInfo]:
     db, table_path = pair
     return db.query_table_schema(table_path)
 
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 059854a5f..80f4557e7 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -19,6 +19,7 @@
 
 from data_diff.abcs.compiler import AbstractCompiler, Compilable
 from data_diff.queries.extras import ApplyFuncAndNormalizeAsString, Checksum, NormalizeAsString
+from data_diff.schema import RawColumnInfo
 from data_diff.utils import ArithString, is_uuid, join_iter, safezip
 from data_diff.queries.api import Expr, table, Select, SKIP, Explain, Code, this
 from data_diff.queries.ast_classes import (
@@ -707,27 +708,18 @@ def type_repr(self, t) -> str:
             datetime: "TIMESTAMP",
         }[t]
 
-    def _parse_type_repr(self, type_repr: str) -> Optional[Type[ColType]]:
-        return self.TYPE_CLASSES.get(type_repr)
-
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        datetime_precision: int = None,
-        numeric_precision: int = None,
-        numeric_scale: int = None,
-    ) -> ColType:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         "Parse type info as returned by the database"
 
-        cls = self._parse_type_repr(type_repr)
+        cls = self.TYPE_CLASSES.get(info.type_repr)
         if cls is None:
-            return UnknownColType(type_repr)
+            return UnknownColType(info.type_repr)
 
         if issubclass(cls, TemporalType):
             return cls(
-                precision=datetime_precision if datetime_precision is not None else DEFAULT_DATETIME_PRECISION,
+                precision=info.datetime_precision
+                if info.datetime_precision is not None
+                else DEFAULT_DATETIME_PRECISION,
                 rounds=self.ROUNDS_ON_PREC_LOSS,
             )
 
@@ -738,22 +730,22 @@ def parse_type(
             return cls()
 
         elif issubclass(cls, Decimal):
-            if numeric_scale is None:
-                numeric_scale = 0  # Needed for Oracle.
-            return cls(precision=numeric_scale)
+            if info.numeric_scale is None:
+                return cls(precision=0)  # Needed for Oracle.
+            return cls(precision=info.numeric_scale)
 
         elif issubclass(cls, Float):
             # assert numeric_scale is None
             return cls(
                 precision=self._convert_db_precision_to_digits(
-                    numeric_precision if numeric_precision is not None else DEFAULT_NUMERIC_PRECISION
+                    info.numeric_precision if info.numeric_precision is not None else DEFAULT_NUMERIC_PRECISION
                 )
             )
 
         elif issubclass(cls, (JSON, Array, Struct, Text, Native_UUID)):
             return cls()
 
-        raise TypeError(f"Parsing {type_repr} returned an unknown type '{cls}'.")
+        raise TypeError(f"Parsing {info.type_repr} returned an unknown type {cls!r}.")
 
     def _convert_db_precision_to_digits(self, p: int) -> int:
         """Convert from binary precision, used by floats, to decimal precision."""
@@ -1018,7 +1010,7 @@ def select_table_schema(self, path: DbPath) -> str:
             f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
         )
 
-    def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
+    def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         """Query the table for its schema for table in 'path', and return {column: tuple}
         where the tuple is (table_name, col_name, type_repr, datetime_precision?, numeric_precision?, numeric_scale?)
 
@@ -1029,7 +1021,17 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
-        d = {r[0]: r for r in rows}
+        d = {
+            r[0]: RawColumnInfo(
+                column_name=r[0],
+                type_repr=r[1],
+                datetime_precision=r[2],
+                numeric_precision=r[3],
+                numeric_scale=r[4],
+                collation_name=r[5] if len(r) > 5 else None,
+            )
+            for r in rows
+        }
         assert len(d) == len(rows)
         return d
 
@@ -1051,7 +1053,11 @@ def query_table_unique_columns(self, path: DbPath) -> List[str]:
         return list(res)
 
     def _process_table_schema(
-        self, path: DbPath, raw_schema: Dict[str, tuple], filter_columns: Sequence[str] = None, where: str = None
+        self,
+        path: DbPath,
+        raw_schema: Dict[str, RawColumnInfo],
+        filter_columns: Sequence[str] = None,
+        where: str = None,
     ):
         """Process the result of query_table_schema().
 
@@ -1067,7 +1073,7 @@ def _process_table_schema(
             accept = {i.lower() for i in filter_columns}
             filtered_schema = {name: row for name, row in raw_schema.items() if name.lower() in accept}
 
-        col_dict = {row[0]: self.dialect.parse_type(path, *row) for _name, row in filtered_schema.items()}
+        col_dict = {info.column_name: self.dialect.parse_type(path, info) for info in filtered_schema.values()}
 
         self._refine_coltypes(path, col_dict, where)
 
@@ -1076,7 +1082,7 @@ def _process_table_schema(
 
     def _refine_coltypes(
         self, table_path: DbPath, col_dict: Dict[str, ColType], where: Optional[str] = None, sample_size=64
-    ):
+    ) -> Dict[str, ColType]:
         """Refine the types in the column dict, by querying the database for a sample of their values
 
         'where' restricts the rows to be sampled.
@@ -1084,7 +1090,7 @@ def _refine_coltypes(
 
         text_columns = [k for k, v in col_dict.items() if isinstance(v, Text)]
         if not text_columns:
-            return
+            return col_dict
 
         fields = [Code(self.dialect.normalize_uuid(self.dialect.quote(c), String_UUID())) for c in text_columns]
 
@@ -1118,6 +1124,8 @@ def _refine_coltypes(
                         assert col_name in col_dict
                         col_dict[col_name] = String_VaryingAlphanum()
 
+        return col_dict
+
     def _normalize_table_path(self, path: DbPath) -> DbPath:
         if len(path) == 1:
             return self.default_schema, path[0]
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 26d8aec3d..02ee4d337 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -33,6 +33,7 @@
     MD5_HEXDIGITS,
 )
 from data_diff.databases.base import TIMESTAMP_PRECISION_POS, ThreadLocalInterpreter
+from data_diff.schema import RawColumnInfo
 
 
 @import_helper(text="Please install BigQuery and configure your google-cloud access.")
@@ -91,19 +92,13 @@ def type_repr(self, t) -> str:
         except KeyError:
             return super().type_repr(t)
 
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        *args: Any,  # pass-through args
-        **kwargs: Any,  # pass-through args
-    ) -> ColType:
-        col_type = super().parse_type(table_path, col_name, type_repr, *args, **kwargs)
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
+        col_type = super().parse_type(table_path, info)
         if isinstance(col_type, UnknownColType):
-            m = self.TYPE_ARRAY_RE.fullmatch(type_repr)
+            m = self.TYPE_ARRAY_RE.fullmatch(info.type_repr)
             if m:
-                item_type = self.parse_type(table_path, col_name, m.group(1), *args, **kwargs)
+                item_info = attrs.evolve(info, data_type=m.group(1))
+                item_type = self.parse_type(table_path, item_info)
                 col_type = Array(item_type=item_type)
 
             # We currently ignore structs' structure, but later can parse it too. Examples:
@@ -111,7 +106,7 @@ def parse_type(
             # - STRUCT<foo INT64, bar STRING(10)> (named)
             # - STRUCT<foo INT64, bar ARRAY<INT64>> (with complex fields)
             # - STRUCT<foo INT64, bar STRUCT<a INT64, b INT64>> (nested)
-            m = self.TYPE_STRUCT_RE.fullmatch(type_repr)
+            m = self.TYPE_STRUCT_RE.fullmatch(info.type_repr)
             if m:
                 col_type = Struct()
 
diff --git a/data_diff/databases/clickhouse.py b/data_diff/databases/clickhouse.py
index 13082504b..a85198af2 100644
--- a/data_diff/databases/clickhouse.py
+++ b/data_diff/databases/clickhouse.py
@@ -14,6 +14,7 @@
 )
 from data_diff.abcs.database_types import (
     ColType,
+    DbPath,
     Decimal,
     Float,
     Integer,
@@ -24,6 +25,7 @@
     Timestamp,
     Boolean,
 )
+from data_diff.schema import RawColumnInfo
 
 # https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/#default-database
 DEFAULT_DATABASE = "default"
@@ -75,19 +77,19 @@ def _convert_db_precision_to_digits(self, p: int) -> int:
         # because it does not help for float with a big integer part.
         return super()._convert_db_precision_to_digits(p) - 2
 
-    def _parse_type_repr(self, type_repr: str) -> Optional[Type[ColType]]:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         nullable_prefix = "Nullable("
-        if type_repr.startswith(nullable_prefix):
-            type_repr = type_repr[len(nullable_prefix) :].rstrip(")")
+        if info.type_repr.startswith(nullable_prefix):
+            info = attrs.evolve(info, data_type=info.type_repr[len(nullable_prefix) :].rstrip(")"))
 
-        if type_repr.startswith("Decimal"):
-            type_repr = "Decimal"
-        elif type_repr.startswith("FixedString"):
-            type_repr = "FixedString"
-        elif type_repr.startswith("DateTime64"):
-            type_repr = "DateTime64"
+        if info.type_repr.startswith("Decimal"):
+            info = attrs.evolve(info, data_type="Decimal")
+        elif info.type_repr.startswith("FixedString"):
+            info = attrs.evolve(info, data_type="FixedString")
+        elif info.type_repr.startswith("DateTime64"):
+            info = attrs.evolve(info, data_type="DateTime64")
 
-        return self.TYPE_CLASSES.get(type_repr)
+        return super().parse_type(table_path, info)
 
     # def timestamp_value(self, t: DbTime) -> str:
     #     # return f"'{t}'"
diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index c755cfa9b..8bb9156a7 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -26,6 +26,7 @@
     import_helper,
     parse_table_name,
 )
+from data_diff.schema import RawColumnInfo
 
 
 @import_helper(text="You can install it using 'pip install databricks-sql-connector'")
@@ -138,7 +139,7 @@ def create_connection(self):
         except databricks.sql.exc.Error as e:
             raise ConnectionError(*e.args) from e
 
-    def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
+    def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         # Databricks has INFORMATION_SCHEMA only for Databricks Runtime, not for Databricks SQL.
         # https://docs.databricks.com/spark/latest/spark-sql/language-manual/information-schema/columns.html
         # So, to obtain information about schema, we should use another approach.
@@ -155,7 +156,12 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
             if not rows:
                 raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
-            d = {r.COLUMN_NAME: (r.COLUMN_NAME, r.TYPE_NAME, r.DECIMAL_DIGITS, None, None) for r in rows}
+            d = {
+                r.COLUMN_NAME: RawColumnInfo(
+                    column_name=r.COLUMN_NAME, type_repr=r.TYPE_NAME, datetime_precision=r.DECIMAL_DIGITS
+                )
+                for r in rows
+            }
             assert len(d) == len(rows)
             return d
 
@@ -173,37 +179,39 @@ def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
     #     )
 
     def _process_table_schema(
-        self, path: DbPath, raw_schema: Dict[str, tuple], filter_columns: Sequence[str], where: str = None
+        self, path: DbPath, raw_schema: Dict[str, RawColumnInfo], filter_columns: Sequence[str], where: str = None
     ):
         accept = {i.lower() for i in filter_columns}
-        rows = [row for name, row in raw_schema.items() if name.lower() in accept]
+        col_infos = [row for name, row in raw_schema.items() if name.lower() in accept]
 
         resulted_rows = []
-        for row in rows:
-            row_type = "DECIMAL" if row[1].startswith("DECIMAL") else row[1]
+        for info in col_infos:
+            row_type = "DECIMAL" if info.type_repr.startswith("DECIMAL") else info.type_repr
+            info = attrs.evolve(info, type_repr=row_type)
             type_cls = self.dialect.TYPE_CLASSES.get(row_type, UnknownColType)
 
             if issubclass(type_cls, Integer):
-                row = (row[0], row_type, None, None, 0)
+                info = attrs.evolve(info, numeric_scale=0)
 
             elif issubclass(type_cls, Float):
-                numeric_precision = math.ceil(row[2] / math.log(2, 10))
-                row = (row[0], row_type, None, numeric_precision, None)
+                numeric_precision = math.ceil(info[2] / math.log(2, 10))
+                info = attrs.evolve(info, numeric_precision=numeric_precision)
 
             elif issubclass(type_cls, Decimal):
-                items = row[1][8:].rstrip(")").split(",")
+                items = info.type_repr[8:].rstrip(")").split(",")
                 numeric_precision, numeric_scale = int(items[0]), int(items[1])
-                row = (row[0], row_type, None, numeric_precision, numeric_scale)
+                info = attrs.evolve(
+                    info,
+                    numeric_precision=numeric_precision,
+                    numeric_scale=numeric_scale,
+                )
 
             elif issubclass(type_cls, Timestamp):
-                row = (row[0], row_type, row[2], None, None)
+                info = attrs.evolve(info, datetime_precision=info.datetime_precision)
 
-            else:
-                row = (row[0], row_type, None, None, None)
+            resulted_rows.append(info)
 
-            resulted_rows.append(row)
-
-        col_dict: Dict[str, ColType] = {row[0]: self.dialect.parse_type(path, *row) for row in resulted_rows}
+        col_dict: Dict[str, ColType] = {info.column_name: self.dialect.parse_type(path, info) for info in resulted_rows}
 
         self._refine_coltypes(path, col_dict, where)
         return col_dict
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index d057e0d90..31536854d 100644
--- a/data_diff/databases/duckdb.py
+++ b/data_diff/databases/duckdb.py
@@ -3,6 +3,7 @@
 import attrs
 from packaging.version import parse as parse_version
 
+from data_diff.schema import RawColumnInfo
 from data_diff.utils import match_regexps
 from data_diff.abcs.database_types import (
     Timestamp,
@@ -74,24 +75,16 @@ def _convert_db_precision_to_digits(self, p: int) -> int:
         # Subtracting 2 due to wierd precision issues in PostgreSQL
         return super()._convert_db_precision_to_digits(p) - 2
 
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        datetime_precision: int = None,
-        numeric_precision: int = None,
-        numeric_scale: int = None,
-    ) -> ColType:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         regexps = {
             r"DECIMAL\((\d+),(\d+)\)": Decimal,
         }
 
-        for m, t_cls in match_regexps(regexps, type_repr):
+        for m, t_cls in match_regexps(regexps, info.type_repr):
             precision = int(m.group(2))
             return t_cls(precision=precision)
 
-        return super().parse_type(table_path, col_name, type_repr, datetime_precision, numeric_precision, numeric_scale)
+        return super().parse_type(table_path, info)
 
     def set_timezone_to_utc(self) -> str:
         return "SET GLOBAL TimeZone='UTC'"
diff --git a/data_diff/databases/oracle.py b/data_diff/databases/oracle.py
index ab84f0b6d..0383b1f15 100644
--- a/data_diff/databases/oracle.py
+++ b/data_diff/databases/oracle.py
@@ -2,6 +2,7 @@
 
 import attrs
 
+from data_diff.schema import RawColumnInfo
 from data_diff.utils import match_regexps
 from data_diff.abcs.database_types import (
     Decimal,
@@ -105,26 +106,18 @@ def constant_values(self, rows) -> str:
     def explain_as_text(self, query: str) -> str:
         raise NotImplementedError("Explain not yet implemented in Oracle")
 
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        datetime_precision: int = None,
-        numeric_precision: int = None,
-        numeric_scale: int = None,
-    ) -> ColType:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         regexps = {
             r"TIMESTAMP\((\d)\) WITH LOCAL TIME ZONE": Timestamp,
             r"TIMESTAMP\((\d)\) WITH TIME ZONE": TimestampTZ,
             r"TIMESTAMP\((\d)\)": Timestamp,
         }
 
-        for m, t_cls in match_regexps(regexps, type_repr):
+        for m, t_cls in match_regexps(regexps, info.type_repr):
             precision = int(m.group(1))
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
-        return super().parse_type(table_path, col_name, type_repr, datetime_precision, numeric_precision, numeric_scale)
+        return super().parse_type(table_path, info)
 
     def set_timezone_to_utc(self) -> str:
         return "ALTER SESSION SET TIME_ZONE = 'UTC'"
diff --git a/data_diff/databases/presto.py b/data_diff/databases/presto.py
index ba1c73606..fa8c1f6d2 100644
--- a/data_diff/databases/presto.py
+++ b/data_diff/databases/presto.py
@@ -4,6 +4,7 @@
 
 import attrs
 
+from data_diff.schema import RawColumnInfo
 from data_diff.utils import match_regexps
 
 from data_diff.abcs.database_types import (
@@ -91,33 +92,25 @@ def quote(self, s: str):
     def to_string(self, s: str):
         return f"cast({s} as varchar)"
 
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        datetime_precision: int = None,
-        numeric_precision: int = None,
-        _numeric_scale: int = None,
-    ) -> ColType:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         timestamp_regexps = {
             r"timestamp\((\d)\)": Timestamp,
             r"timestamp\((\d)\) with time zone": TimestampTZ,
         }
-        for m, t_cls in match_regexps(timestamp_regexps, type_repr):
+        for m, t_cls in match_regexps(timestamp_regexps, info.type_repr):
             precision = int(m.group(1))
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
         number_regexps = {r"decimal\((\d+),(\d+)\)": Decimal}
-        for m, n_cls in match_regexps(number_regexps, type_repr):
+        for m, n_cls in match_regexps(number_regexps, info.type_repr):
             _prec, scale = map(int, m.groups())
             return n_cls(scale)
 
         string_regexps = {r"varchar\((\d+)\)": Text, r"char\((\d+)\)": Text}
-        for m, n_cls in match_regexps(string_regexps, type_repr):
+        for m, n_cls in match_regexps(string_regexps, info.type_repr):
             return n_cls()
 
-        return super().parse_type(table_path, col_name, type_repr, datetime_precision, numeric_precision)
+        return super().parse_type(table_path, info)
 
     def set_timezone_to_utc(self) -> str:
         return "SET TIME ZONE '+00:00'"
diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index 44e86b17a..1c2aa3b6d 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -1,4 +1,4 @@
-from typing import ClassVar, List, Dict, Type
+from typing import Any, ClassVar, Iterable, List, Dict, Tuple, Type
 
 import attrs
 
@@ -20,6 +20,7 @@
     TIMESTAMP_PRECISION_POS,
     PostgresqlDialect,
 )
+from data_diff.schema import RawColumnInfo
 
 
 @attrs.define(frozen=False)
@@ -96,13 +97,12 @@ def select_external_table_schema(self, path: DbPath) -> str:
             + db_clause
         )
 
-    def query_external_table_schema(self, path: DbPath) -> Dict[str, tuple]:
+    def query_external_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         rows = self.query(self.select_external_table_schema(path), list)
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
         schema_dict = self._normalize_schema_info(rows)
-
         return schema_dict
 
     def select_view_columns(self, path: DbPath) -> str:
@@ -112,14 +112,12 @@ def select_view_columns(self, path: DbPath) -> str:
                 cols(col_name name, col_type varchar)
             """.format(schema, table)
 
-    def query_pg_get_cols(self, path: DbPath) -> Dict[str, tuple]:
+    def query_pg_get_cols(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         rows = self.query(self.select_view_columns(path), list)
-
         if not rows:
             raise RuntimeError(f"{self.name}: View '{'.'.join(path)}' does not exist, or has no columns")
 
         schema_dict = self._normalize_schema_info(rows)
-
         return schema_dict
 
     def select_svv_columns_schema(self, path: DbPath) -> Dict[str, tuple]:
@@ -145,19 +143,29 @@ def select_svv_columns_schema(self, path: DbPath) -> Dict[str, tuple]:
             + db_clause
         )
 
-    def query_svv_columns(self, path: DbPath) -> Dict[str, tuple]:
+    def query_svv_columns(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         rows = self.query(self.select_svv_columns_schema(path), list)
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
-        d = {r[0]: r for r in rows}
+        d = {
+            r[0]: RawColumnInfo(
+                column_name=r[0],
+                type_repr=r[1],
+                datetime_precision=r[2],
+                numeric_precision=r[3],
+                numeric_scale=r[4],
+                collation_name=r[5] if len(r) > 5 else None,
+            )
+            for r in rows
+        }
         assert len(d) == len(rows)
         return d
 
     # when using a non-information_schema source, strip (N) from type(N) etc. to match
     # typical information_schema output
-    def _normalize_schema_info(self, rows) -> Dict[str, tuple]:
-        schema_dict = {}
+    def _normalize_schema_info(self, rows: Iterable[Tuple[Any]]) -> Dict[str, RawColumnInfo]:
+        schema_dict: Dict[str, RawColumnInfo] = {}
         for r in rows:
             col_name = r[0]
             type_info = r[1].split("(")
@@ -171,11 +179,17 @@ def _normalize_schema_info(self, rows) -> Dict[str, tuple]:
                     precision = int(precision)
                     scale = int(scale)
 
-            out = [col_name, base_type, None, precision, scale]
-            schema_dict[col_name] = tuple(out)
+            schema_dict[col_name] = RawColumnInfo(
+                column_name=col_name,
+                type_repr=col_name,
+                datetime_precision=None,
+                numeric_precision=precision,
+                numeric_scale=scale,
+                collation_name=None,
+            )
         return schema_dict
 
-    def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
+    def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         try:
             return super().query_table_schema(path)
         except RuntimeError:
diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index 23f63accd..8a0e329e4 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -2,6 +2,7 @@
 
 import attrs
 
+from data_diff.schema import RawColumnInfo
 from data_diff.utils import match_regexps
 from data_diff.databases.base import (
     CHECKSUM_HEXDIGITS,
@@ -68,27 +69,19 @@ def to_string(self, s: str) -> str:
     def is_distinct_from(self, a: str, b: str) -> str:
         return f"not ({a} <=> {b})"
 
-    def parse_type(
-        self,
-        table_path: DbPath,
-        col_name: str,
-        type_repr: str,
-        datetime_precision: int = None,
-        numeric_precision: int = None,
-        numeric_scale: int = None,
-    ) -> ColType:
+    def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         timestamp_regexps = {
             r"timestamp\(?(\d?)\)?": Timestamp,
             r"timestamptz\(?(\d?)\)?": TimestampTZ,
         }
-        for m, t_cls in match_regexps(timestamp_regexps, type_repr):
+        for m, t_cls in match_regexps(timestamp_regexps, info.type_repr):
             precision = int(m.group(1)) if m.group(1) else 6
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
         number_regexps = {
             r"numeric\((\d+),(\d+)\)": Decimal,
         }
-        for m, n_cls in match_regexps(number_regexps, type_repr):
+        for m, n_cls in match_regexps(number_regexps, info.type_repr):
             _prec, scale = map(int, m.groups())
             return n_cls(scale)
 
@@ -96,10 +89,10 @@ def parse_type(
             r"varchar\((\d+)\)": Text,
             r"char\((\d+)\)": Text,
         }
-        for m, n_cls in match_regexps(string_regexps, type_repr):
+        for m, n_cls in match_regexps(string_regexps, info.type_repr):
             return n_cls()
 
-        return super().parse_type(table_path, col_name, type_repr, datetime_precision, numeric_precision)
+        return super().parse_type(table_path, info)
 
     def set_timezone_to_utc(self) -> str:
         return "SET TIME ZONE TO 'UTC'"
diff --git a/data_diff/dbt.py b/data_diff/dbt.py
index 92a1fdbe2..a7ab343df 100644
--- a/data_diff/dbt.py
+++ b/data_diff/dbt.py
@@ -303,7 +303,7 @@ def _local_diff(
     columns_removed = table1_column_names.difference(table2_column_names)
     # col type is i = 1 in tuple
     columns_type_changed = {
-        k for k, v in table2_columns.items() if k in table1_columns and v[1] != table1_columns[k][1]
+        k for k, v in table2_columns.items() if k in table1_columns and v.type_repr != table1_columns[k].type_repr
     }
 
     if columns_added:
diff --git a/data_diff/schema.py b/data_diff/schema.py
index 67b4261f1..5f1734ef4 100644
--- a/data_diff/schema.py
+++ b/data_diff/schema.py
@@ -1,4 +1,7 @@
 import logging
+from typing import Any, Collection, Iterable, Optional
+
+import attrs
 
 from data_diff.utils import CaseAwareMapping, CaseInsensitiveDict, CaseSensitiveDict
 from data_diff.abcs.database_types import DbPath
@@ -8,6 +11,35 @@
 Schema = CaseAwareMapping
 
 
+@attrs.frozen(kw_only=True)
+class RawColumnInfo(Collection[Any]):
+    """
+    A raw row representing the schema info about a column.
+
+    Do not rely on this class too much, it will be removed soon when the schema
+    selecting & parsing methods are united into one overrideable method.
+    """
+
+    column_name: str
+    type_repr: str
+    datetime_precision: Optional[int] = None
+    numeric_precision: Optional[int] = None
+    numeric_scale: Optional[int] = None
+    collation_name: Optional[str] = None
+
+    # It was a tuple once, so we keep it backward compatible temporarily, until remade to classes.
+    def __iter__(self) -> Iterable[Any]:
+        return iter(
+            (self.column_name, self.type_repr, self.datetime_precision, self.numeric_precision, self.numeric_scale)
+        )
+
+    def __len__(self) -> int:
+        return 5
+
+    def __contains__(self, item: Any) -> bool:
+        return False  # that was not used
+
+
 def create_schema(db_name: str, table_path: DbPath, schema: dict, case_sensitive: bool) -> CaseAwareMapping:
     logger.info(f"[{db_name}] Schema = {schema}")
 
diff --git a/data_diff/table_segment.py b/data_diff/table_segment.py
index 2cf81a708..73b12909f 100644
--- a/data_diff/table_segment.py
+++ b/data_diff/table_segment.py
@@ -1,5 +1,5 @@
 import time
-from typing import Container, List, Optional, Tuple
+from typing import Container, Dict, List, Optional, Tuple
 import logging
 from itertools import product
 
@@ -10,7 +10,7 @@
 from data_diff.utils import ArithString, split_space
 from data_diff.databases.base import Database
 from data_diff.abcs.database_types import DbPath, DbKey, DbTime
-from data_diff.schema import Schema, create_schema
+from data_diff.schema import RawColumnInfo, Schema, create_schema
 from data_diff.queries.extras import Checksum
 from data_diff.queries.api import Count, SKIP, table, this, Expr, min_, max_, Code
 from data_diff.queries.extras import ApplyFuncAndNormalizeAsString, NormalizeAsString
@@ -141,7 +141,7 @@ def __attrs_post_init__(self):
     def _where(self):
         return f"({self.where})" if self.where else None
 
-    def _with_raw_schema(self, raw_schema: dict) -> Self:
+    def _with_raw_schema(self, raw_schema: Dict[str, RawColumnInfo]) -> Self:
         schema = self.database._process_table_schema(self.table_path, raw_schema, self.relevant_columns, self._where())
         return self.new(schema=create_schema(self.database.name, self.table_path, schema, self.case_sensitive))
 
@@ -152,7 +152,7 @@ def with_schema(self) -> Self:
 
         return self._with_raw_schema(self.database.query_table_schema(self.table_path))
 
-    def get_schema(self):
+    def get_schema(self) -> Dict[str, RawColumnInfo]:
         return self.database.query_table_schema(self.table_path)
 
     def _make_key_range(self):
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index c56765539..eb05a4c58 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -22,6 +22,7 @@
 from data_diff.dbt_parser import (
     TDatadiffConfig,
 )
+from data_diff.schema import RawColumnInfo
 from tests.test_cli import run_datadiff_cli
 
 
@@ -75,7 +76,10 @@ def test_integration_cloud_dbt(self):
     def test_local_diff(self, mock_diff_tables):
         connection = {}
         mock_table1 = Mock()
-        column_dictionary = {"col1": ("col1", "type"), "col2": ("col2", "type")}
+        column_dictionary = {
+            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
+            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+        }
         mock_table1.get_schema.return_value = column_dictionary
         mock_table2 = Mock()
         mock_table2.get_schema.return_value = column_dictionary
@@ -120,8 +124,14 @@ def test_local_diff_types_differ(self, mock_diff_tables):
         connection = {}
         mock_table1 = Mock()
         mock_table2 = Mock()
-        table1_column_dictionary = {"col1": ("col1", "type"), "col2": ("col2", "type")}
-        table2_column_dictionary = {"col1": ("col1", "type"), "col2": ("col2", "differing_type")}
+        table1_column_dictionary = {
+            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
+            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+        }
+        table2_column_dictionary = {
+            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
+            "col2": RawColumnInfo(column_name="col2", type_repr="differing_type"),
+        }
         mock_table1.get_schema.return_value = table1_column_dictionary
         mock_table2.get_schema.return_value = table2_column_dictionary
         mock_diff = MagicMock()
@@ -161,7 +171,10 @@ def test_local_diff_types_differ(self, mock_diff_tables):
     @patch("data_diff.dbt.diff_tables")
     def test_local_diff_no_diffs(self, mock_diff_tables):
         connection = {}
-        column_dictionary = {"col1": ("col1", "type"), "col2": ("col2", "type")}
+        column_dictionary = {
+            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
+            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+        }
         mock_table1 = Mock()
         mock_table1.get_schema.return_value = column_dictionary
         mock_table2 = Mock()

From fedcef66c62b2ebd4118ec95b8e4adf3b166a513 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 27 Dec 2023 13:41:57 +0100
Subject: [PATCH 47/99] Rename "type_repr" to "data_type" to align with
 conventional information schemas

---
 data_diff/databases/base.py       |  8 ++++----
 data_diff/databases/bigquery.py   |  4 ++--
 data_diff/databases/clickhouse.py | 10 +++++-----
 data_diff/databases/databricks.py |  8 ++++----
 data_diff/databases/duckdb.py     |  2 +-
 data_diff/databases/oracle.py     |  2 +-
 data_diff/databases/presto.py     |  6 +++---
 data_diff/databases/redshift.py   |  4 ++--
 data_diff/databases/vertica.py    |  6 +++---
 data_diff/dbt.py                  |  2 +-
 data_diff/schema.py               |  4 ++--
 tests/test_dbt.py                 | 16 ++++++++--------
 12 files changed, 36 insertions(+), 36 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 80f4557e7..a3583ad6e 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -711,9 +711,9 @@ def type_repr(self, t) -> str:
     def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         "Parse type info as returned by the database"
 
-        cls = self.TYPE_CLASSES.get(info.type_repr)
+        cls = self.TYPE_CLASSES.get(info.data_type)
         if cls is None:
-            return UnknownColType(info.type_repr)
+            return UnknownColType(info.data_type)
 
         if issubclass(cls, TemporalType):
             return cls(
@@ -745,7 +745,7 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         elif issubclass(cls, (JSON, Array, Struct, Text, Native_UUID)):
             return cls()
 
-        raise TypeError(f"Parsing {info.type_repr} returned an unknown type {cls!r}.")
+        raise TypeError(f"Parsing {info.data_type} returned an unknown type {cls!r}.")
 
     def _convert_db_precision_to_digits(self, p: int) -> int:
         """Convert from binary precision, used by floats, to decimal precision."""
@@ -1024,7 +1024,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         d = {
             r[0]: RawColumnInfo(
                 column_name=r[0],
-                type_repr=r[1],
+                data_type=r[1],
                 datetime_precision=r[2],
                 numeric_precision=r[3],
                 numeric_scale=r[4],
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 02ee4d337..afe61d4e0 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -95,7 +95,7 @@ def type_repr(self, t) -> str:
     def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         col_type = super().parse_type(table_path, info)
         if isinstance(col_type, UnknownColType):
-            m = self.TYPE_ARRAY_RE.fullmatch(info.type_repr)
+            m = self.TYPE_ARRAY_RE.fullmatch(info.data_type)
             if m:
                 item_info = attrs.evolve(info, data_type=m.group(1))
                 item_type = self.parse_type(table_path, item_info)
@@ -106,7 +106,7 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             # - STRUCT<foo INT64, bar STRING(10)> (named)
             # - STRUCT<foo INT64, bar ARRAY<INT64>> (with complex fields)
             # - STRUCT<foo INT64, bar STRUCT<a INT64, b INT64>> (nested)
-            m = self.TYPE_STRUCT_RE.fullmatch(info.type_repr)
+            m = self.TYPE_STRUCT_RE.fullmatch(info.data_type)
             if m:
                 col_type = Struct()
 
diff --git a/data_diff/databases/clickhouse.py b/data_diff/databases/clickhouse.py
index a85198af2..7bbc156f6 100644
--- a/data_diff/databases/clickhouse.py
+++ b/data_diff/databases/clickhouse.py
@@ -79,14 +79,14 @@ def _convert_db_precision_to_digits(self, p: int) -> int:
 
     def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         nullable_prefix = "Nullable("
-        if info.type_repr.startswith(nullable_prefix):
-            info = attrs.evolve(info, data_type=info.type_repr[len(nullable_prefix) :].rstrip(")"))
+        if info.data_type.startswith(nullable_prefix):
+            info = attrs.evolve(info, data_type=info.data_type[len(nullable_prefix) :].rstrip(")"))
 
-        if info.type_repr.startswith("Decimal"):
+        if info.data_type.startswith("Decimal"):
             info = attrs.evolve(info, data_type="Decimal")
-        elif info.type_repr.startswith("FixedString"):
+        elif info.data_type.startswith("FixedString"):
             info = attrs.evolve(info, data_type="FixedString")
-        elif info.type_repr.startswith("DateTime64"):
+        elif info.data_type.startswith("DateTime64"):
             info = attrs.evolve(info, data_type="DateTime64")
 
         return super().parse_type(table_path, info)
diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index 8bb9156a7..0421b2040 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -158,7 +158,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
 
             d = {
                 r.COLUMN_NAME: RawColumnInfo(
-                    column_name=r.COLUMN_NAME, type_repr=r.TYPE_NAME, datetime_precision=r.DECIMAL_DIGITS
+                    column_name=r.COLUMN_NAME, data_type=r.TYPE_NAME, datetime_precision=r.DECIMAL_DIGITS
                 )
                 for r in rows
             }
@@ -186,8 +186,8 @@ def _process_table_schema(
 
         resulted_rows = []
         for info in col_infos:
-            row_type = "DECIMAL" if info.type_repr.startswith("DECIMAL") else info.type_repr
-            info = attrs.evolve(info, type_repr=row_type)
+            row_type = "DECIMAL" if info.data_type.startswith("DECIMAL") else info.data_type
+            info = attrs.evolve(info, data_type=row_type)
             type_cls = self.dialect.TYPE_CLASSES.get(row_type, UnknownColType)
 
             if issubclass(type_cls, Integer):
@@ -198,7 +198,7 @@ def _process_table_schema(
                 info = attrs.evolve(info, numeric_precision=numeric_precision)
 
             elif issubclass(type_cls, Decimal):
-                items = info.type_repr[8:].rstrip(")").split(",")
+                items = info.data_type[8:].rstrip(")").split(",")
                 numeric_precision, numeric_scale = int(items[0]), int(items[1])
                 info = attrs.evolve(
                     info,
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index 31536854d..069735c42 100644
--- a/data_diff/databases/duckdb.py
+++ b/data_diff/databases/duckdb.py
@@ -80,7 +80,7 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             r"DECIMAL\((\d+),(\d+)\)": Decimal,
         }
 
-        for m, t_cls in match_regexps(regexps, info.type_repr):
+        for m, t_cls in match_regexps(regexps, info.data_type):
             precision = int(m.group(2))
             return t_cls(precision=precision)
 
diff --git a/data_diff/databases/oracle.py b/data_diff/databases/oracle.py
index 0383b1f15..2f6537be1 100644
--- a/data_diff/databases/oracle.py
+++ b/data_diff/databases/oracle.py
@@ -113,7 +113,7 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             r"TIMESTAMP\((\d)\)": Timestamp,
         }
 
-        for m, t_cls in match_regexps(regexps, info.type_repr):
+        for m, t_cls in match_regexps(regexps, info.data_type):
             precision = int(m.group(1))
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
diff --git a/data_diff/databases/presto.py b/data_diff/databases/presto.py
index fa8c1f6d2..034ac99fd 100644
--- a/data_diff/databases/presto.py
+++ b/data_diff/databases/presto.py
@@ -97,17 +97,17 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             r"timestamp\((\d)\)": Timestamp,
             r"timestamp\((\d)\) with time zone": TimestampTZ,
         }
-        for m, t_cls in match_regexps(timestamp_regexps, info.type_repr):
+        for m, t_cls in match_regexps(timestamp_regexps, info.data_type):
             precision = int(m.group(1))
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
         number_regexps = {r"decimal\((\d+),(\d+)\)": Decimal}
-        for m, n_cls in match_regexps(number_regexps, info.type_repr):
+        for m, n_cls in match_regexps(number_regexps, info.data_type):
             _prec, scale = map(int, m.groups())
             return n_cls(scale)
 
         string_regexps = {r"varchar\((\d+)\)": Text, r"char\((\d+)\)": Text}
-        for m, n_cls in match_regexps(string_regexps, info.type_repr):
+        for m, n_cls in match_regexps(string_regexps, info.data_type):
             return n_cls()
 
         return super().parse_type(table_path, info)
diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index 1c2aa3b6d..be9ec0fb0 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -151,7 +151,7 @@ def query_svv_columns(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         d = {
             r[0]: RawColumnInfo(
                 column_name=r[0],
-                type_repr=r[1],
+                data_type=r[1],
                 datetime_precision=r[2],
                 numeric_precision=r[3],
                 numeric_scale=r[4],
@@ -181,7 +181,7 @@ def _normalize_schema_info(self, rows: Iterable[Tuple[Any]]) -> Dict[str, RawCol
 
             schema_dict[col_name] = RawColumnInfo(
                 column_name=col_name,
-                type_repr=col_name,
+                data_type=col_name,
                 datetime_precision=None,
                 numeric_precision=precision,
                 numeric_scale=scale,
diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index 8a0e329e4..6fbc88e16 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -74,14 +74,14 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             r"timestamp\(?(\d?)\)?": Timestamp,
             r"timestamptz\(?(\d?)\)?": TimestampTZ,
         }
-        for m, t_cls in match_regexps(timestamp_regexps, info.type_repr):
+        for m, t_cls in match_regexps(timestamp_regexps, info.data_type):
             precision = int(m.group(1)) if m.group(1) else 6
             return t_cls(precision=precision, rounds=self.ROUNDS_ON_PREC_LOSS)
 
         number_regexps = {
             r"numeric\((\d+),(\d+)\)": Decimal,
         }
-        for m, n_cls in match_regexps(number_regexps, info.type_repr):
+        for m, n_cls in match_regexps(number_regexps, info.data_type):
             _prec, scale = map(int, m.groups())
             return n_cls(scale)
 
@@ -89,7 +89,7 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
             r"varchar\((\d+)\)": Text,
             r"char\((\d+)\)": Text,
         }
-        for m, n_cls in match_regexps(string_regexps, info.type_repr):
+        for m, n_cls in match_regexps(string_regexps, info.data_type):
             return n_cls()
 
         return super().parse_type(table_path, info)
diff --git a/data_diff/dbt.py b/data_diff/dbt.py
index a7ab343df..2da076e96 100644
--- a/data_diff/dbt.py
+++ b/data_diff/dbt.py
@@ -303,7 +303,7 @@ def _local_diff(
     columns_removed = table1_column_names.difference(table2_column_names)
     # col type is i = 1 in tuple
     columns_type_changed = {
-        k for k, v in table2_columns.items() if k in table1_columns and v.type_repr != table1_columns[k].type_repr
+        k for k, v in table2_columns.items() if k in table1_columns and v.data_type != table1_columns[k].data_type
     }
 
     if columns_added:
diff --git a/data_diff/schema.py b/data_diff/schema.py
index 5f1734ef4..f04089355 100644
--- a/data_diff/schema.py
+++ b/data_diff/schema.py
@@ -21,7 +21,7 @@ class RawColumnInfo(Collection[Any]):
     """
 
     column_name: str
-    type_repr: str
+    data_type: str
     datetime_precision: Optional[int] = None
     numeric_precision: Optional[int] = None
     numeric_scale: Optional[int] = None
@@ -30,7 +30,7 @@ class RawColumnInfo(Collection[Any]):
     # It was a tuple once, so we keep it backward compatible temporarily, until remade to classes.
     def __iter__(self) -> Iterable[Any]:
         return iter(
-            (self.column_name, self.type_repr, self.datetime_precision, self.numeric_precision, self.numeric_scale)
+            (self.column_name, self.data_type, self.datetime_precision, self.numeric_precision, self.numeric_scale)
         )
 
     def __len__(self) -> int:
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index eb05a4c58..0cf943284 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -77,8 +77,8 @@ def test_local_diff(self, mock_diff_tables):
         connection = {}
         mock_table1 = Mock()
         column_dictionary = {
-            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
-            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+            "col1": RawColumnInfo(column_name="col1", data_type="type"),
+            "col2": RawColumnInfo(column_name="col2", data_type="type"),
         }
         mock_table1.get_schema.return_value = column_dictionary
         mock_table2 = Mock()
@@ -125,12 +125,12 @@ def test_local_diff_types_differ(self, mock_diff_tables):
         mock_table1 = Mock()
         mock_table2 = Mock()
         table1_column_dictionary = {
-            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
-            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+            "col1": RawColumnInfo(column_name="col1", data_type="type"),
+            "col2": RawColumnInfo(column_name="col2", data_type="type"),
         }
         table2_column_dictionary = {
-            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
-            "col2": RawColumnInfo(column_name="col2", type_repr="differing_type"),
+            "col1": RawColumnInfo(column_name="col1", data_type="type"),
+            "col2": RawColumnInfo(column_name="col2", data_type="differing_type"),
         }
         mock_table1.get_schema.return_value = table1_column_dictionary
         mock_table2.get_schema.return_value = table2_column_dictionary
@@ -172,8 +172,8 @@ def test_local_diff_types_differ(self, mock_diff_tables):
     def test_local_diff_no_diffs(self, mock_diff_tables):
         connection = {}
         column_dictionary = {
-            "col1": RawColumnInfo(column_name="col1", type_repr="type"),
-            "col2": RawColumnInfo(column_name="col2", type_repr="type"),
+            "col1": RawColumnInfo(column_name="col1", data_type="type"),
+            "col2": RawColumnInfo(column_name="col2", data_type="type"),
         }
         mock_table1 = Mock()
         mock_table1.get_schema.return_value = column_dictionary

From 9e83b7d1de220838c3a1792c5b3c3cad81324b0a Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Mon, 18 Dec 2023 15:36:28 +0100
Subject: [PATCH 48/99] Retrieve collations for selected databases (SQL Server
 & Snowflake)

---
 data_diff/abcs/database_types.py | 88 +++++++++++++++++++++++++++++++-
 data_diff/databases/base.py      |  2 +-
 data_diff/databases/mssql.py     |  2 +-
 data_diff/databases/snowflake.py |  3 +-
 4 files changed, 91 insertions(+), 4 deletions(-)

diff --git a/data_diff/abcs/database_types.py b/data_diff/abcs/database_types.py
index f3c6381a0..b6912b4ae 100644
--- a/data_diff/abcs/database_types.py
+++ b/data_diff/abcs/database_types.py
@@ -1,6 +1,6 @@
 import decimal
 from abc import ABC, abstractmethod
-from typing import List, Optional, Tuple, Type, TypeVar, Union
+from typing import Collection, List, Optional, Tuple, Type, TypeVar, Union
 from datetime import datetime
 
 import attrs
@@ -15,6 +15,91 @@
 N = TypeVar("N")
 
 
+@attrs.frozen(kw_only=True, eq=False, order=False, unsafe_hash=True)
+class Collation:
+    """
+    A pre-parsed or pre-known record about db collation, per column.
+
+    The "greater" collation should be used as a target collation for textual PKs
+    on both sides of the diff — by coverting the "lesser" collation to self.
+
+    Snowflake easily absorbs the performance losses, so it has a boost to always
+    be greater than any other collation in non-Snowflake databases.
+    Other databases need to negotiate which side absorbs the performance impact.
+    """
+
+    # A boost for special databases that are known to absorb the performance dmaage well.
+    absorbs_damage: bool = False
+
+    # Ordinal soring by ASCII/UTF8 (True), or alphabetic as per locale/country/etc (False).
+    ordinal: Optional[bool] = None
+
+    # Lowercase first (aAbBcC or abcABC). Otherwise, uppercase first (AaBbCc or ABCabc).
+    lower_first: Optional[bool] = None
+
+    # 2-letter lower-case locale and upper-case country codes, e.g. en_US. Ignored for ordinals.
+    language: Optional[str] = None
+    country: Optional[str] = None
+
+    # There are also space-, punctuation-, width-, kana-(in)sensitivity, so on.
+    # Ignore everything not related to xdb alignment. Only case- & accent-sensitivity are common.
+    case_sensitive: Optional[bool] = None
+    accent_sensitive: Optional[bool] = None
+
+    # Purely informational, for debugging:
+    _source: Union[None, str, Collection[str]] = None
+
+    def __eq__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        if self.ordinal and other.ordinal:
+            # TODO: does it depend on language? what does Albanic_BIN mean in MS SQL?
+            return True
+        return (
+            self.language == other.language
+            and (self.country is None or other.country is None or self.country == other.country)
+            and self.case_sensitive == other.case_sensitive
+            and self.accent_sensitive == other.accent_sensitive
+            and self.lower_first == other.lower_first
+        )
+
+    def __ne__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        return not self.__eq__(other)
+
+    def __gt__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        if self == other:
+            return False
+        if self.absorbs_damage and not other.absorbs_damage:
+            return False
+        if other.absorbs_damage and not self.absorbs_damage:
+            return True  # this one is preferred if it cannot absorb damage as its counterpart can
+        if self.ordinal and not other.ordinal:
+            return True
+        if other.ordinal and not self.ordinal:
+            return False
+        # TODO: try to align the languages & countries?
+        return False
+
+    def __ge__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        return self == other or self.__gt__(other)
+
+    def __lt__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        return self != other and not self.__gt__(other)
+
+    def __le__(self, other: object) -> bool:
+        if not isinstance(other, Collation):
+            return NotImplemented
+        return self == other or not self.__gt__(other)
+
+
 @attrs.define(frozen=True, kw_only=True)
 class ColType:
     # Arbitrary metadata added and fetched at runtime.
@@ -112,6 +197,7 @@ def python_type(self) -> type:
 @attrs.define(frozen=True)
 class StringType(ColType):
     python_type = str
+    collation: Optional[Collation] = attrs.field(default=None, kw_only=True)
 
 
 @attrs.define(frozen=True)
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index a3583ad6e..d6738e7ee 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -1122,7 +1122,7 @@ def _refine_coltypes(
                         )
                     else:
                         assert col_name in col_dict
-                        col_dict[col_name] = String_VaryingAlphanum()
+                        col_dict[col_name] = String_VaryingAlphanum(collation=col_dict[col_name].collation)
 
         return col_dict
 
diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index 834ed9cd3..758ac3e81 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -201,7 +201,7 @@ def select_table_schema(self, path: DbPath) -> str:
             info_schema_path.insert(0, self.dialect.quote(database))
 
         return (
-            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale "
+            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale, collation_name "
             f"FROM {'.'.join(info_schema_path)} "
             f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
         )
diff --git a/data_diff/databases/snowflake.py b/data_diff/databases/snowflake.py
index 4152a407c..1b70085a5 100644
--- a/data_diff/databases/snowflake.py
+++ b/data_diff/databases/snowflake.py
@@ -164,7 +164,8 @@ def select_table_schema(self, path: DbPath) -> str:
             info_schema_path.insert(0, database)
 
         return (
-            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale "
+            "SELECT column_name, data_type, datetime_precision, numeric_precision, numeric_scale"
+            "   , coalesce(collation_name, 'utf8') "
             f"FROM {'.'.join(info_schema_path)} "
             f"WHERE table_name = '{name}' AND table_schema = '{schema}'"
         )

From a9cfd54f1b7f061dbec84e429d85e3522d351dab Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Fri, 29 Dec 2023 14:31:21 -0700
Subject: [PATCH 49/99] option to yield list of diffs, prioritize base calls to
 _bisect_and_diff_segments

Otherwise the info_tree is missing key ranges for the majority of execution
---
 data_diff/diff_tables.py  | 14 +++++++++-----
 data_diff/thread_utils.py |  9 +++++++--
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 518cc1227..6de54898f 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -6,7 +6,7 @@
 from enum import Enum
 from contextlib import contextmanager
 from operator import methodcaller
-from typing import Dict, Set, Tuple, Iterator, Optional
+from typing import Dict, Set, List, Tuple, Iterator, Optional
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 import attrs
@@ -28,6 +28,7 @@ class Algorithm(Enum):
 
 
 DiffResult = Iterator[Tuple[str, tuple]]  # Iterator[Tuple[Literal["+", "-"], tuple]]
+DiffResultList = Iterator[List[Tuple[str, tuple]]]
 
 
 @attrs.define(frozen=False)
@@ -187,6 +188,7 @@ class TableDiffer(ThreadBase, ABC):
     ignored_columns1: Set[str] = attrs.field(factory=set)
     ignored_columns2: Set[str] = attrs.field(factory=set)
     _ignored_columns_lock: threading.Lock = attrs.field(factory=threading.Lock, init=False)
+    yield_list: bool = False
 
     def diff_tables(self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree = None) -> DiffResultWrapper:
         """Diff the given tables.
@@ -255,7 +257,9 @@ def _diff_tables_wrapper(self, table1: TableSegment, table2: TableSegment, info_
     def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegment) -> None:
         pass
 
-    def _diff_tables_root(self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree) -> DiffResult:
+    def _diff_tables_root(
+        self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree
+    ) -> DiffResult | DiffResultList:
         return self._bisect_and_diff_tables(table1, table2, info_tree)
 
     @abstractmethod
@@ -300,9 +304,9 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
             f"size: table1 <= {btable1.approximate_size()}, table2 <= {btable2.approximate_size()}"
         )
 
-        ti = ThreadedYielder(self.max_threadpool_size)
+        ti = ThreadedYielder(self.max_threadpool_size, self.yield_list)
         # Bisect (split) the table into segments, and diff them recursively.
-        ti.submit(self._bisect_and_diff_segments, ti, btable1, btable2, info_tree)
+        ti.submit(self._bisect_and_diff_segments, ti, btable1, btable2, info_tree, priority=999)
 
         # Now we check for the second min-max, to diff the portions we "missed".
         # This is achieved by subtracting the table ranges, and dividing the resulting space into aligned boxes.
@@ -326,7 +330,7 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
 
         for p1, p2 in new_regions:
             extra_tables = [t.new_key_bounds(min_key=p1, max_key=p2) for t in (table1, table2)]
-            ti.submit(self._bisect_and_diff_segments, ti, *extra_tables, info_tree)
+            ti.submit(self._bisect_and_diff_segments, ti, *extra_tables, info_tree, priority=999)
 
         return ti
 
diff --git a/data_diff/thread_utils.py b/data_diff/thread_utils.py
index 55b2d9d56..ba292ef54 100644
--- a/data_diff/thread_utils.py
+++ b/data_diff/thread_utils.py
@@ -56,19 +56,24 @@ class ThreadedYielder(Iterable):
     _futures: deque
     _yield: deque = attrs.field(alias="_yield")  # Python keyword!
     _exception: Optional[None]
+    yield_list: bool
 
-    def __init__(self, max_workers: Optional[int] = None):
+    def __init__(self, max_workers: Optional[int] = None, yield_list: bool = False):
         super().__init__()
         self._pool = PriorityThreadPoolExecutor(max_workers)
         self._futures = deque()
         self._yield = deque()
         self._exception = None
+        self.yield_list = yield_list
 
     def _worker(self, fn, *args, **kwargs):
         try:
             res = fn(*args, **kwargs)
             if res is not None:
-                self._yield += res
+                if self.yield_list:
+                    self._yield.append(res)
+                else:
+                    self._yield += res
         except Exception as e:
             self._exception = e
 

From 00db9a4eba3488816e01dd090fd4a60fd2a1230b Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sat, 30 Dec 2023 17:12:19 +0100
Subject: [PATCH 50/99] Make InfoTree classes overrideable

---
 data_diff/diff_tables.py | 5 ++++-
 data_diff/info_tree.py   | 8 ++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 6de54898f..9eb8b531a 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -182,6 +182,8 @@ def get_stats_dict(self, is_dbt: bool = False):
 
 @attrs.define(frozen=False)
 class TableDiffer(ThreadBase, ABC):
+    INFO_TREE_CLASS = InfoTree
+
     bisection_factor = 32
     stats: dict = {}
 
@@ -204,7 +206,8 @@ def diff_tables(self, table1: TableSegment, table2: TableSegment, info_tree: Inf
             Where `row` is a tuple of values, corresponding to the diffed columns.
         """
         if info_tree is None:
-            info_tree = InfoTree(SegmentInfo([table1, table2]))
+            segment_info = self.INFO_TREE_CLASS.SEGMENT_INFO_CLASS([table1, table2])
+            info_tree = self.INFO_TREE_CLASS(segment_info)
         return DiffResultWrapper(self._diff_tables_wrapper(table1, table2, info_tree), info_tree, self.stats)
 
     def _diff_tables_wrapper(self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree) -> DiffResult:
diff --git a/data_diff/info_tree.py b/data_diff/info_tree.py
index d08eb16dc..bc9430de1 100644
--- a/data_diff/info_tree.py
+++ b/data_diff/info_tree.py
@@ -1,6 +1,7 @@
 from typing import List, Dict, Optional, Any, Tuple, Union
 
 import attrs
+from typing_extensions import Self
 
 from data_diff.table_segment import TableSegment
 
@@ -41,11 +42,14 @@ def update_from_children(self, child_infos):
 
 @attrs.define(frozen=True)
 class InfoTree:
+    SEGMENT_INFO_CLASS = SegmentInfo
+
     info: SegmentInfo
     children: List["InfoTree"] = attrs.field(factory=list)
 
-    def add_node(self, table1: TableSegment, table2: TableSegment, max_rows: int = None):
-        node = InfoTree(SegmentInfo([table1, table2], max_rows=max_rows))
+    def add_node(self, table1: TableSegment, table2: TableSegment, max_rows: Optional[int] = None) -> Self:
+        cls = self.__class__
+        node = cls(cls.SEGMENT_INFO_CLASS([table1, table2], max_rows=max_rows))
         self.children.append(node)
         return node
 

From bf5f60d8f0070815052afe503138e4596f10063f Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sat, 30 Dec 2023 18:34:31 +0100
Subject: [PATCH 51/99] Make code compatible with Python 3.8

---
 data_diff/diff_tables.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 9eb8b531a..4aa09da27 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -6,7 +6,7 @@
 from enum import Enum
 from contextlib import contextmanager
 from operator import methodcaller
-from typing import Dict, Set, List, Tuple, Iterator, Optional
+from typing import Dict, Set, List, Tuple, Iterator, Optional, Union
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 import attrs
@@ -262,7 +262,7 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
 
     def _diff_tables_root(
         self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree
-    ) -> DiffResult | DiffResultList:
+    ) -> Union[DiffResult, DiffResultList]:
         return self._bisect_and_diff_tables(table1, table2, info_tree)
 
     @abstractmethod

From 79b6c8992913fd84deeb12d6fcef25333ffbe4b1 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sat, 30 Dec 2023 17:03:10 +0100
Subject: [PATCH 52/99] Cast to unlimited varchars in MS SQL (especially UUDS)

---
 data_diff/databases/mssql.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index 758ac3e81..c54446105 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -94,7 +94,8 @@ def current_schema(self) -> str:
         WHERE name = CURRENT_USER"""
 
     def to_string(self, s: str):
-        return f"CONVERT(varchar, {s})"
+        # Both convert(varchar(max), …) and convert(text, …) do work.
+        return f"CONVERT(VARCHAR(MAX), {s})"
 
     def type_repr(self, t) -> str:
         try:

From 50c1595c54ef1ee6a1cdcf631e077db85edda72e Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 27 Dec 2023 12:44:48 +0100
Subject: [PATCH 53/99] Cease detecting MD5 hashes as UUIDs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It fails the comparison anyway — because of casing & dashes not fitting into alphanumeric ranges/slices.
---
 data_diff/utils.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/data_diff/utils.py b/data_diff/utils.py
index b9045cc13..a93bdfe61 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -43,7 +43,14 @@ def safezip(*args):
     return zip(*args)
 
 
-def is_uuid(u):
+UUID_PATTERN = re.compile(r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", re.I)
+
+
+def is_uuid(u: str) -> bool:
+    # E.g., hashlib.md5(b'hello') is a 32-letter hex number, but not an UUID.
+    # It would fail UUID-like comparison (< & >) because of casing and dashes.
+    if not UUID_PATTERN.fullmatch(u):
+        return False
     try:
         UUID(u)
     except ValueError:

From 871d8e2a0be9180ce32b2614496bd20c34d84434 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 27 Dec 2023 12:47:06 +0100
Subject: [PATCH 54/99] Refactor UUID & ArithUUID from inheritance into
 composition

---
 data_diff/databases/base.py |  9 ++++--
 data_diff/utils.py          | 63 ++++++++++++++++++++++++++++++++-----
 2 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index d6738e7ee..4a4e10a2d 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -20,7 +20,7 @@
 from data_diff.abcs.compiler import AbstractCompiler, Compilable
 from data_diff.queries.extras import ApplyFuncAndNormalizeAsString, Checksum, NormalizeAsString
 from data_diff.schema import RawColumnInfo
-from data_diff.utils import ArithString, is_uuid, join_iter, safezip
+from data_diff.utils import ArithString, ArithUUID, is_uuid, join_iter, safezip
 from data_diff.queries.api import Expr, table, Select, SKIP, Explain, Code, this
 from data_diff.queries.ast_classes import (
     Alias,
@@ -248,6 +248,9 @@ def _compile(self, compiler: Compiler, elem) -> str:
             return self.timestamp_value(elem)
         elif isinstance(elem, bytes):
             return f"b'{elem.decode()}'"
+        elif isinstance(elem, ArithUUID):
+            s = f"'{elem.uuid}'"
+            return s
         elif isinstance(elem, ArithString):
             return f"'{elem}'"
         assert False, elem
@@ -681,8 +684,10 @@ def _constant_value(self, v):
             return f"'{v}'"
         elif isinstance(v, datetime):
             return self.timestamp_value(v)
-        elif isinstance(v, UUID):
+        elif isinstance(v, UUID):  # probably unused anymore in favour of ArithUUID
             return f"'{v}'"
+        elif isinstance(v, ArithUUID):
+            return f"'{v.uuid}'"
         elif isinstance(v, decimal.Decimal):
             return str(v)
         elif isinstance(v, bytearray):
diff --git a/data_diff/utils.py b/data_diff/utils.py
index a93bdfe61..e52702db7 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -135,23 +135,70 @@ def range(self, other: "ArithString", count: int) -> List[Self]:
         return [self.new(int=i) for i in checkpoints]
 
 
-# @attrs.define  # not as long as it inherits from UUID
-class ArithUUID(UUID, ArithString):
+def _any_to_uuid(v: Union[str, int, UUID]) -> UUID:
+    if isinstance(v, UUID):
+        return v
+    elif isinstance(v, str):
+        return UUID(v)
+    elif isinstance(v, int):
+        return UUID(int=v)
+    else:
+        raise ValueError(f"Cannot convert a value to UUID: {v!r}")
+
+
+@attrs.define(frozen=True, eq=False, order=False)
+class ArithUUID(ArithString):
     "A UUID that supports basic arithmetic (add, sub)"
 
+    uuid: UUID = attrs.field(converter=_any_to_uuid)
+    def range(self, other: "ArithUUID", count: int) -> List[Self]:
+        assert isinstance(other, ArithUUID)
+        checkpoints = split_space(self.uuid.int, other.uuid.int, count)
+        return [attrs.evolve(self, uuid=i) for i in checkpoints]
+
     def __int__(self):
-        return self.int
+        return self.uuid.int
 
     def __add__(self, other: int) -> Self:
         if isinstance(other, int):
-            return self.new(int=self.int + other)
+            return attrs.evolve(self, uuid=self.uuid.int + other)
         return NotImplemented
 
-    def __sub__(self, other: Union[UUID, int]):
+    def __sub__(self, other: Union["ArithUUID", int]):
         if isinstance(other, int):
-            return self.new(int=self.int - other)
-        elif isinstance(other, UUID):
-            return self.int - other.int
+            return attrs.evolve(self, uuid=self.uuid.int - other)
+        elif isinstance(other, ArithUUID):
+            return self.uuid.int - other.uuid.int
+        return NotImplemented
+
+    def __eq__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid == other.uuid
+        return NotImplemented
+
+    def __ne__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid != other.uuid
+        return NotImplemented
+
+    def __gt__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid > other.uuid
+        return NotImplemented
+
+    def __lt__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid < other.uuid
+        return NotImplemented
+
+    def __ge__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid >= other.uuid
+        return NotImplemented
+
+    def __le__(self, other: object) -> bool:
+        if isinstance(other, ArithUUID):
+            return self.uuid <= other.uuid
         return NotImplemented
 
 

From e8ec55b2407804c8cfb6ee9b85a050aa888eca22 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 27 Dec 2023 12:47:50 +0100
Subject: [PATCH 55/99] Preserve lower-/upper-case mode of UUIDs and render
 them back accordingly

---
 data_diff/abcs/database_types.py | 9 ++++++++-
 data_diff/databases/base.py      | 7 +++++--
 data_diff/utils.py               | 3 +++
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/data_diff/abcs/database_types.py b/data_diff/abcs/database_types.py
index b6912b4ae..14436438a 100644
--- a/data_diff/abcs/database_types.py
+++ b/data_diff/abcs/database_types.py
@@ -217,7 +217,14 @@ class Native_UUID(ColType_UUID):
 
 @attrs.define(frozen=True)
 class String_UUID(ColType_UUID, StringType):
-    pass
+    # Case is important for UUIDs stored as regular string, not native UUIDs stored as numbers.
+    # We slice them internally as numbers, but render them back to SQL as lower/upper case.
+    # None means we do not know for sure, behave as with False, but it might be unreliable.
+    lowercase: Optional[bool] = None
+    uppercase: Optional[bool] = None
+
+    def make_value(self, v: str) -> ArithUUID:
+        return self.python_type(v, lowercase=self.lowercase, uppercase=self.uppercase)
 
 
 @attrs.define(frozen=True)
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 4a4e10a2d..21c8d0e63 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -250,7 +250,7 @@ def _compile(self, compiler: Compiler, elem) -> str:
             return f"b'{elem.decode()}'"
         elif isinstance(elem, ArithUUID):
             s = f"'{elem.uuid}'"
-            return s
+            return s.upper() if elem.uppercase else s.lower() if elem.lowercase else s
         elif isinstance(elem, ArithString):
             return f"'{elem}'"
         assert False, elem
@@ -1115,7 +1115,10 @@ def _refine_coltypes(
                     )
                 else:
                     assert col_name in col_dict
-                    col_dict[col_name] = String_UUID()
+                    col_dict[col_name] = String_UUID(
+                        lowercase=all(s == s.lower() for s in uuid_samples),
+                        uppercase=all(s == s.upper() for s in uuid_samples),
+                    )
                     continue
 
             if self.SUPPORTS_ALPHANUMS:  # Anything but MySQL (so far)
diff --git a/data_diff/utils.py b/data_diff/utils.py
index e52702db7..6a5388131 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -151,6 +151,9 @@ class ArithUUID(ArithString):
     "A UUID that supports basic arithmetic (add, sub)"
 
     uuid: UUID = attrs.field(converter=_any_to_uuid)
+    lowercase: Optional[bool] = None
+    uppercase: Optional[bool] = None
+
     def range(self, other: "ArithUUID", count: int) -> List[Self]:
         assert isinstance(other, ArithUUID)
         checkpoints = split_space(self.uuid.int, other.uuid.int, count)

From 9a9903047e916bdcd7d977ec107cbc53cb649d95 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Thu, 28 Dec 2023 11:40:59 +0100
Subject: [PATCH 56/99] Restore the proper meta-params of PK column type
 relevant to each side when slicing

Otherwise, it uses the same PK values, e.g. `ArithUUID` from the side A, and then pushes them to side B, where improper rendering can lead to improper slicing.
---
 data_diff/abcs/database_types.py |   7 +-
 data_diff/diff_tables.py         |  11 ++-
 data_diff/table_segment.py       |  13 ++-
 data_diff/utils.py               |   6 +-
 tests/test_mesh.py               | 132 +++++++++++++++++++++++++++++++
 5 files changed, 157 insertions(+), 12 deletions(-)
 create mode 100644 tests/test_mesh.py

diff --git a/data_diff/abcs/database_types.py b/data_diff/abcs/database_types.py
index 14436438a..e5aa5fab5 100644
--- a/data_diff/abcs/database_types.py
+++ b/data_diff/abcs/database_types.py
@@ -182,6 +182,8 @@ def python_type(self) -> type:
         "Return the equivalent Python type of the key"
 
     def make_value(self, value):
+        if isinstance(value, self.python_type):
+            return value
         return self.python_type(value)
 
 
@@ -237,9 +239,6 @@ def test_value(value: str) -> bool:
         except ValueError:
             return False
 
-    def make_value(self, value):
-        return self.python_type(value)
-
 
 @attrs.define(frozen=True)
 class String_VaryingAlphanum(String_Alphanum):
@@ -251,6 +250,8 @@ class String_FixedAlphanum(String_Alphanum):
     length: int
 
     def make_value(self, value):
+        if isinstance(value, self.python_type):
+            return value
         if len(value) != self.length:
             raise ValueError(f"Expected alphanumeric value of length {self.length}, but got '{value}'.")
         return self.python_type(value, max_len=self.length)
diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 4aa09da27..5ec1f71b1 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -300,7 +300,8 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
         # Start with the first completed value, so we don't waste time waiting
         min_key1, max_key1 = self._parse_key_range_result(key_types1, next(key_ranges))
 
-        btable1, btable2 = [t.new_key_bounds(min_key=min_key1, max_key=max_key1) for t in (table1, table2)]
+        btable1 = table1.new_key_bounds(min_key=min_key1, max_key=max_key1, key_types=key_types1)
+        btable2 = table2.new_key_bounds(min_key=min_key1, max_key=max_key1, key_types=key_types2)
 
         logger.info(
             f"Diffing segments at key-range: {btable1.min_key}..{btable2.max_key}. "
@@ -324,7 +325,8 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
         # └──┴──────┴──┘
         # Overall, the max number of new regions in this 2nd pass is 3^|k| - 1
 
-        min_key2, max_key2 = self._parse_key_range_result(key_types1, next(key_ranges))
+        # Note: python types can be the same, but the rendering parameters (e.g. casing) can differ.
+        min_key2, max_key2 = self._parse_key_range_result(key_types2, next(key_ranges))
 
         points = [list(sorted(p)) for p in safezip(min_key1, min_key2, max_key1, max_key2)]
         box_mesh = create_mesh_from_points(*points)
@@ -332,8 +334,9 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
         new_regions = [(p1, p2) for p1, p2 in box_mesh if p1 < p2 and not (p1 >= min_key1 and p2 <= max_key1)]
 
         for p1, p2 in new_regions:
-            extra_tables = [t.new_key_bounds(min_key=p1, max_key=p2) for t in (table1, table2)]
-            ti.submit(self._bisect_and_diff_segments, ti, *extra_tables, info_tree, priority=999)
+            extra_table1 = table1.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types1)
+            extra_table2 = table2.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types2)
+            ti.submit(self._bisect_and_diff_segments, ti, extra_table1, extra_table2, info_tree, priority=999)
 
         return ti
 
diff --git a/data_diff/table_segment.py b/data_diff/table_segment.py
index 73b12909f..924271bac 100644
--- a/data_diff/table_segment.py
+++ b/data_diff/table_segment.py
@@ -1,5 +1,5 @@
 import time
-from typing import Container, Dict, List, Optional, Tuple
+from typing import Container, Dict, List, Optional, Sequence, Tuple
 import logging
 from itertools import product
 
@@ -9,7 +9,7 @@
 from data_diff.utils import safezip, Vector
 from data_diff.utils import ArithString, split_space
 from data_diff.databases.base import Database
-from data_diff.abcs.database_types import DbPath, DbKey, DbTime
+from data_diff.abcs.database_types import DbPath, DbKey, DbTime, IKey
 from data_diff.schema import RawColumnInfo, Schema, create_schema
 from data_diff.queries.extras import Checksum
 from data_diff.queries.api import Count, SKIP, table, this, Expr, min_, max_, Code
@@ -205,7 +205,7 @@ def new(self, **kwargs) -> Self:
         """Creates a copy of the instance using 'replace()'"""
         return attrs.evolve(self, **kwargs)
 
-    def new_key_bounds(self, min_key: Vector, max_key: Vector) -> Self:
+    def new_key_bounds(self, min_key: Vector, max_key: Vector, *, key_types: Optional[Sequence[IKey]] = None) -> Self:
         if self.min_key is not None:
             assert self.min_key <= min_key, (self.min_key, min_key)
             assert self.min_key < max_key
@@ -214,6 +214,13 @@ def new_key_bounds(self, min_key: Vector, max_key: Vector) -> Self:
             assert min_key < self.max_key
             assert max_key <= self.max_key
 
+        # If asked, enforce the PKs to proper types, mainly to meta-params of the relevant side,
+        # so that we do not leak e.g. casing of UUIDs from side A to side B and vice versa.
+        # If not asked, keep the meta-params of the keys as is (assume them already casted).
+        if key_types is not None:
+            min_key = Vector(type.make_value(val) for type, val in safezip(key_types, min_key))
+            max_key = Vector(type.make_value(val) for type, val in safezip(key_types, max_key))
+
         return attrs.evolve(self, min_key=min_key, max_key=max_key)
 
     @property
diff --git a/data_diff/utils.py b/data_diff/utils.py
index 6a5388131..e16110e11 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -135,8 +135,10 @@ def range(self, other: "ArithString", count: int) -> List[Self]:
         return [self.new(int=i) for i in checkpoints]
 
 
-def _any_to_uuid(v: Union[str, int, UUID]) -> UUID:
-    if isinstance(v, UUID):
+def _any_to_uuid(v: Union[str, int, UUID, "ArithUUID"]) -> UUID:
+    if isinstance(v, ArithUUID):
+        return v.uuid
+    elif isinstance(v, UUID):
         return v
     elif isinstance(v, str):
         return UUID(v)
diff --git a/tests/test_mesh.py b/tests/test_mesh.py
new file mode 100644
index 000000000..c0ee7c554
--- /dev/null
+++ b/tests/test_mesh.py
@@ -0,0 +1,132 @@
+import uuid
+
+from data_diff.abcs.database_types import String_UUID
+from data_diff.databases import MySQL
+from data_diff.table_segment import create_mesh_from_points
+from data_diff.utils import ArithUUID, safezip
+from tests.common import DiffTestCase, table_segment
+
+
+# We do not need real tables, just any reference to them for proper object creation.
+class TestDiffMesh(DiffTestCase):
+    db_cls = MySQL
+
+    def test_meta_parameters_passed_from_coltypes_to_values(self):
+        key_types1 = [String_UUID(lowercase=True, uppercase=False)]
+        key_types2 = [String_UUID(lowercase=False, uppercase=True)]
+
+        # side B is wider than side A to ensure there are "outer" regions.
+        min_uuid1 = uuid.UUID("11111111-1111-1111-1111-111111111111")
+        max_uuid1 = uuid.UUID("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE")
+        min_uuid2 = uuid.UUID("00000000-0000-0000-0000-000000000000")
+        max_uuid2 = uuid.UUID("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
+        min_key1 = (key_types1[0].make_value(min_uuid1),)
+        max_key1 = (key_types1[0].make_value(max_uuid1),)
+        min_key2 = (key_types2[0].make_value(min_uuid2),)
+        max_key2 = (key_types2[0].make_value(max_uuid2),)
+
+        # Verify that we pass the meta-parameters from col types to values:
+        assert isinstance(min_key1[0], ArithUUID)
+        assert isinstance(max_key1[0], ArithUUID)
+        assert isinstance(min_key2[0], ArithUUID)
+        assert isinstance(max_key2[0], ArithUUID)
+        assert min_key1[0].uuid == min_uuid1
+        assert min_key1[0].lowercase == True
+        assert min_key1[0].uppercase == False
+        assert max_key1[0].uuid == max_uuid1
+        assert max_key1[0].lowercase == True
+        assert max_key1[0].uppercase == False
+        assert min_key2[0].uuid == min_uuid2
+        assert min_key2[0].lowercase == False
+        assert min_key2[0].uppercase == True
+        assert max_key2[0].uuid == max_uuid2
+        assert max_key2[0].lowercase == False
+        assert max_key2[0].uppercase == True
+
+    def test_meta_parameters_left_as_is_if_not_casted(self):
+        table1 = table_segment(self.connection, self.table_src_path, "id", "timestamp", case_sensitive=False)
+        key_types1 = [String_UUID(lowercase=True, uppercase=False)]
+
+        min_uuid1 = uuid.UUID("11111111-1111-1111-1111-111111111111")
+        max_uuid1 = uuid.UUID("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE")
+        min_key1 = (key_types1[0].make_value(min_uuid1),)
+        max_key1 = (key_types1[0].make_value(max_uuid1),)
+
+        btable1 = table1.new_key_bounds(min_key=min_key1, max_key=max_key1)
+        assert btable1.min_key[0] is min_key1[0]  # by identity, not by equality
+        assert btable1.max_key[0] is max_key1[0]  # by identity, not by equality
+
+    def test_mesh_keys_meta_parameters_preserved(self):
+        table1 = table_segment(self.connection, self.table_src_path, "id", "timestamp", case_sensitive=False)
+        table2 = table_segment(self.connection, self.table_src_path, "id", "timestamp", case_sensitive=False)
+        key_types1 = [String_UUID(lowercase=True, uppercase=False)]
+        key_types2 = [String_UUID(lowercase=False, uppercase=True)]
+
+        # side B is wider than side A to ensure there are "outer" regions.
+        min_uuid1 = uuid.UUID("11111111-1111-1111-1111-111111111111")
+        max_uuid1 = uuid.UUID("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE")
+        min_uuid2 = uuid.UUID("00000000-0000-0000-0000-000000000000")
+        max_uuid2 = uuid.UUID("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
+        min_key1 = (key_types1[0].make_value(min_uuid1),)
+        max_key1 = (key_types1[0].make_value(max_uuid1),)
+        min_key2 = (key_types2[0].make_value(min_uuid2),)
+        max_key2 = (key_types2[0].make_value(max_uuid2),)
+
+        # This is what TableDiffer._bisect_and_diff_tables() does, precisely (yes, using key1!):
+        btable1 = table1.new_key_bounds(min_key=min_key1, max_key=max_key1, key_types=key_types1)
+        btable2 = table2.new_key_bounds(min_key=min_key1, max_key=max_key1, key_types=key_types2)
+
+        # Verify that both sides have proper (the side-specific) pk meta-parameters:
+        assert btable1.min_key[0].uuid == min_uuid1
+        assert btable1.min_key[0].lowercase == True
+        assert btable1.min_key[0].uppercase == False
+        assert btable1.max_key[0].uuid == max_uuid1
+        assert btable1.max_key[0].lowercase == True
+        assert btable1.max_key[0].uppercase == False
+        assert btable2.min_key[0].uuid == min_uuid1
+        assert btable2.min_key[0].lowercase == False
+        assert btable2.min_key[0].uppercase == True
+        assert btable2.max_key[0].uuid == max_uuid1
+        assert btable2.max_key[0].lowercase == False
+        assert btable2.max_key[0].uppercase == True
+
+        # This is what TableDiffer._bisect_and_diff_tables() does, precisely:
+        points = [list(sorted(p)) for p in safezip(min_key1, min_key2, max_key1, max_key2)]
+        box_mesh = create_mesh_from_points(*points)
+        new_regions = [(p1, p2) for p1, p2 in box_mesh if p1 < p2 and not (p1 >= min_key1 and p2 <= max_key1)]
+        extra_tables = [
+            (
+                table1.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types1),
+                table2.new_key_bounds(min_key=p1, max_key=p2, key_types=key_types2),
+            )
+            for p1, p2 in new_regions
+        ]
+
+        # Verify that extra ("outer") segments have the proper pk meta-parameters:
+        assert len(extra_tables) == 2
+
+        assert extra_tables[0][0].min_key[0].uuid == min_uuid2
+        assert extra_tables[0][0].min_key[0].lowercase == True
+        assert extra_tables[0][0].min_key[0].uppercase == False
+        assert extra_tables[0][0].max_key[0].uuid == min_uuid1
+        assert extra_tables[0][0].max_key[0].lowercase == True
+        assert extra_tables[0][0].max_key[0].uppercase == False
+        assert extra_tables[0][1].min_key[0].uuid == min_uuid2
+        assert extra_tables[0][1].min_key[0].lowercase == False
+        assert extra_tables[0][1].min_key[0].uppercase == True
+        assert extra_tables[0][1].max_key[0].uuid == min_uuid1
+        assert extra_tables[0][1].max_key[0].lowercase == False
+        assert extra_tables[0][1].max_key[0].uppercase == True
+
+        assert extra_tables[1][0].min_key[0].uuid == max_uuid1
+        assert extra_tables[1][0].min_key[0].lowercase == True
+        assert extra_tables[1][0].min_key[0].uppercase == False
+        assert extra_tables[1][0].max_key[0].uuid == max_uuid2
+        assert extra_tables[1][0].max_key[0].lowercase == True
+        assert extra_tables[1][0].max_key[0].uppercase == False
+        assert extra_tables[1][1].min_key[0].uuid == max_uuid1
+        assert extra_tables[1][1].min_key[0].lowercase == False
+        assert extra_tables[1][1].min_key[0].uppercase == True
+        assert extra_tables[1][1].max_key[0].uuid == max_uuid2
+        assert extra_tables[1][1].max_key[0].lowercase == False
+        assert extra_tables[1][1].max_key[0].uppercase == True

From 6886ecc6ae3c15f7bb615801fed6ed2fd90834c4 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sat, 30 Dec 2023 20:11:22 +0100
Subject: [PATCH 57/99] Update the locked setuptools to fix he CI issues

---
 poetry.lock | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/poetry.lock b/poetry.lock
index e07c24027..073367c0c 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -324,6 +324,7 @@ python-versions = ">=3.7, <4"
 files = [
     {file = "clickhouse-driver-0.2.6.tar.gz", hash = "sha256:028baf4d65a0b3f9e0ac5df248cab20657b51adbfce6c5427aa6c16a7318dda1"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e61d975081b74cae9efe7a64b1de1a8aec5643affb81b57487dcae7d195f250f"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee0395b49bd8c0cd3dca6b3a4b9db347c1d300de83ee7b4f482a9d48b6c7af54"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d8aff4d3f0d78fd4b11e28ef344a5ee71d6850fef4a79e3265e0728b4d1d89"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b086bd658889af10205cb8307b714c8202bdfd05a4833fc7f4f82df2d88a963"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a1b6815d56a03398110c7f602a87ad767ecfd7a0869e61f2d8bfa0779dce2b"},
@@ -337,6 +338,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1960244de84d7888598180e69689d1ba7ec6c9c99cd2c080a76315a7a29a5cab"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:5a6bdfde4e2fb81414200303950ba75c3f7ee9249e4a997854ce18e1cb4beea9"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef0a9453a972ec32399cc93a510aec33fa4b9b1f0c5050a3a40e5d298a89a7aa"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:95c13374741a8749980436603922ad7c476ae3b5e17850c50faba3879db66bdb"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d715d392eaadb43ded1c104354aebbc233f69bbf3919aa61beb7cc6ecdaa950a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d75d50265616a2779d0b2acaebf7253783e2b8ad0df3efa6d23f0db1c9bf50"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32f0e02c28e9a6f1c1f116d1aa14772e73beb7efd4f30490d9f171d39b40551a"},
@@ -349,6 +351,20 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3bdff826074af1b339fe9bff17844f6b8117080f895b8601f536b13a9d04f82a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win32.whl", hash = "sha256:c8c02606eabe4288045bbba497088b7fe976c34330c1066db9744fa09fef4a2a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:44df94940739a72a02716bb14ac8b683aef84b54b05783d96201ff334bcd88fb"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:079708ac620343736c2c8dace6663178156f4ded47bf25245b56147498d0d7de"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e13369cf516df6c33c156fe66cfff502f66fc25f2a515c761ed1480fc83b3aa9"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbc0bf957fc6d0163ee06ac02275bdb2f40d109fc225366e387358e78d968a43"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58b0ffb434fefe99b7419e09d6071a49773e9eb49c5ebeedf7c3180b40c2330"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0746dac9aa5cf2c275187aef16b67ae922ef257c82671948a6be86e19ee9cb2"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f1ce40c9a2715ea44be9a5c33cb5b08048c1ef5595a6739443473e4ba23fedf"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9499a2b2d5e856c7e8efd28da479df8a962e2497c70bf5e2d9a25875d520465"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8b2e849bb7102365a480d9d1083ed203a244f0c02a0fc973eab6078b3d14638d"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5846c50e2dfe0ce2f300275955a20f82422b1128b09ab5a9ea4d8a00d4ba8438"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:a12990b54b92b2a2598f144388e766d6261492408f2434738fe649423371894b"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:af14a5699fea890a1f8f022c624ca9f61994e15913cfaf4e0e58b1e4ac99540a"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:965fb8370eb7ee8a20cdf54d7c2fe024f587da692bd15e94dd2eee93a3c88f4b"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-win32.whl", hash = "sha256:9c552205d2b6125a99121080417c5c7bbc47af81ed15bb5ff9be464fed96bb68"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:a58fb8b12a32d58ce0c72839293ec5bacc7904f3db36a82bb963f394dbb5f230"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f2a9abb8b1464985f7a480f956744736e611970ffc8ffd3eb0b46343a3a691e6"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e01696c450a2de41d586689dbaed0893d4de7469811abd3bf831a0483e723a"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0bb85760dabbef493aec985ad94612132ddeb5b81569cf0a7222f6cb7278eda"},
@@ -363,6 +379,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:48f47694d5e54af192a4aa2a24f947795c362ab40a253d088593880fede97568"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b783e5d3d12947c73d991bceb6b8765231512ab0ac6363823cdcd2c283c67a99"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d24e0acf8fef1d787851ae048e0168b2fb10297c3235cbb87974f78db37d3d3"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27dc025f10a930aed453eec5ed9a0404e7b2db671da4a253109facf5c1ad1b4c"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d534c744b1b211241f8c58d2ad5fcfc465a0503011d9b9073c00e25507abcbf3"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:858b8039a1241591b63f368de9dbdef6c4e6466b6bf0e01d53d36f7091af7569"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21eb62e1de7d2d5483d121d1447e857030bf866d4f23572b0dedc515f9359cd0"},
@@ -376,6 +393,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win32.whl", hash = "sha256:b9b775f70371a7333ac828fe2bbd9473c94e18728ac6b70b2865cdee1f0d551f"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:d13fe44620750abcd4c93c067d6e44c8a1ea050856c4c27a5633ad8ff197a689"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e17995752eef4f742976abab03ff3f5b81edb9b9218b151abaf3534055fcf2b8"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c23baf4b4185b3ee13332c05c201e242600e35deb8b0b0d95211e71d5eb3f59"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbd7e3e33d2bc5f32da2557e97299340a722f948790494a2e9efaed4635ff499"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c872e9fee17d278816fc30b4df4b10bedd8eec9efaa614c71725f147b00b30d"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c8af2761676cd306962a86cc87a4187efcfdaf253a0d908c8f8ef791277a7fe"},
@@ -999,6 +1017,16 @@ files = [
     {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -1448,8 +1476,6 @@ files = [
     {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
     {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
     {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
-    {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
-    {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
     {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
@@ -1956,13 +1982,13 @@ jeepney = ">=0.6"
 
 [[package]]
 name = "setuptools"
-version = "69.0.2"
+version = "69.0.3"
 description = "Easily download, build, install, upgrade, and uninstall Python packages"
 optional = false
 python-versions = ">=3.8"
 files = [
-    {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"},
-    {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"},
+    {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"},
+    {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"},
 ]
 
 [package.extras]

From 7db4f45ca0c360458e568bcd575c015abcb7c2cf Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sat, 30 Dec 2023 23:59:44 +0100
Subject: [PATCH 58/99] Fix precision fetching for DataBricks

---
 data_diff/databases/databricks.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index 0421b2040..23ec7df2a 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -158,7 +158,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
 
             d = {
                 r.COLUMN_NAME: RawColumnInfo(
-                    column_name=r.COLUMN_NAME, data_type=r.TYPE_NAME, datetime_precision=r.DECIMAL_DIGITS
+                    column_name=r.COLUMN_NAME, data_type=r.TYPE_NAME, numeric_precision=r.DECIMAL_DIGITS
                 )
                 for r in rows
             }
@@ -194,7 +194,7 @@ def _process_table_schema(
                 info = attrs.evolve(info, numeric_scale=0)
 
             elif issubclass(type_cls, Float):
-                numeric_precision = math.ceil(info[2] / math.log(2, 10))
+                numeric_precision = math.ceil(info.numeric_precision / math.log(2, 10))
                 info = attrs.evolve(info, numeric_precision=numeric_precision)
 
             elif issubclass(type_cls, Decimal):
@@ -207,7 +207,14 @@ def _process_table_schema(
                 )
 
             elif issubclass(type_cls, Timestamp):
-                info = attrs.evolve(info, datetime_precision=info.datetime_precision)
+                info = attrs.evolve(
+                    info,
+                    datetime_precision=info.numeric_precision,
+                    numeric_precision=None,
+                )
+
+            else:
+                info = attrs.evolve(info, numeric_precision=None)
 
             resulted_rows.append(info)
 

From 047502ed8ec3c2712e6de5ae5784bd0bb21d4dcc Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Tue, 2 Jan 2024 12:33:32 +0100
Subject: [PATCH 59/99] Tolerate column type mismatches in non-strict mode

---
 data_diff/hashdiff_tables.py | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 82f33369d..3fb53dd96 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -111,8 +111,11 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
             col1 = table1._schema[c1]
             col2 = table2._schema[c2]
             if isinstance(col1, PrecisionType):
-                if strict and not isinstance(col2, PrecisionType):
-                    raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
+                if not isinstance(col2, PrecisionType):
+                    if strict:
+                        raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
+                    else:
+                        continue
 
                 lowest = min(col1, col2, key=lambda col: col.precision)
 
@@ -123,8 +126,11 @@ def _validate_and_adjust_columns(self, table1: TableSegment, table2: TableSegmen
                 table2._schema[c2] = attrs.evolve(col2, precision=lowest.precision, rounds=lowest.rounds)
 
             elif isinstance(col1, (NumericType, Boolean)):
-                if strict and not isinstance(col2, (NumericType, Boolean)):
-                    raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
+                if not isinstance(col2, (NumericType, Boolean)):
+                    if strict:
+                        raise TypeError(f"Incompatible types for column '{c1}':  {col1} <-> {col2}")
+                    else:
+                        continue
 
                 lowest = min(col1, col2, key=lambda col: col.precision)
 

From e3f6315d710ed04013f41ebf21e6d39c5757052d Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 3 Jan 2024 06:00:17 +1300
Subject: [PATCH 60/99] Update ruff formatter to work differently between forks
 and native branches (#821)

* add unformatted file

* test github action

* add conditional suggestion

* fix condition

* try again

* try again

* try diff output

* fork repo conditions

* fix format test

* helpful error message

* put it in the name

* shorten sentence

* fix formatting

* revert changes

* consistent behavior to skipping database tests

* ruff format

* verify none

* ruff format

* empty string or none condition

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
Co-authored-by: Dan Lawin <daniel@datafold.com>
---
 .github/workflows/formatter.yml | 16 ++++++++++++++--
 tests/test_dbt.py               |  4 ++++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/formatter.yml b/.github/workflows/formatter.yml
index c1860fdf7..384c34c37 100644
--- a/.github/workflows/formatter.yml
+++ b/.github/workflows/formatter.yml
@@ -21,13 +21,25 @@ jobs:
         uses: actions/checkout@v3
         if: github.event_name == 'workflow_dispatch'
 
-      - name: Check files using the ruff formatter
+      # This is used for forked PRs as write permissions are required to format files
+      - name: Run and commit changes with `ruff format .` locally on your forked branch to fix errors if they appear
+        if: ${{ github.event.pull_request.head.repo.fork == true }}
+        uses: chartboost/ruff-action@v1
+        id: ruff_formatter_suggestions
+        with:
+          args: format --diff
+
+      # This only runs if the PR is NOT from a forked repo
+      - name: Format files using ruff
+        if: ${{ github.event.pull_request.head.repo.fork == false }}
         uses: chartboost/ruff-action@v1
         id: ruff_formatter
         with:
           args: format
 
+      # This only runs if the PR is NOT from a forked repo
       - name: Auto commit ruff formatting
+        if: ${{ github.event.pull_request.head.repo.fork == false }}
         uses: stefanzweifel/git-auto-commit-action@v5
         with:
-          commit_message: 'style fixes by ruff'
\ No newline at end of file
+          commit_message: 'style fixes by ruff'
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index 0cf943284..74faba70b 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -46,6 +46,10 @@ def test_integration_basic_dbt(self):
             # 1 with a diff
             assert diff_string.count("  Rows Added    Rows Removed") == 1
 
+    @unittest.skipIf(
+        not os.environ.get("MOTHERDUCK_TOKEN"),
+        "MOTHERDUCK_TOKEN doesn't exist or is empty if this is run from a forked branch pull request",
+    )
     def test_integration_motherduck_dbt(self):
         artifacts_path = os.getcwd() + "/tests/dbt_artifacts"
         test_project_path = os.environ.get("DATA_DIFF_DBT_PROJ") or artifacts_path

From 060e8cb67944001104ecc41c3ae845785dfe718d Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 2 Jan 2024 14:13:59 -0700
Subject: [PATCH 61/99] keep precision, scale info for databricks decimal

---
 data_diff/databases/databricks.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index 23ec7df2a..b867d90df 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -186,6 +186,7 @@ def _process_table_schema(
 
         resulted_rows = []
         for info in col_infos:
+            raw_data_type = info.data_type
             row_type = "DECIMAL" if info.data_type.startswith("DECIMAL") else info.data_type
             info = attrs.evolve(info, data_type=row_type)
             type_cls = self.dialect.TYPE_CLASSES.get(row_type, UnknownColType)
@@ -198,7 +199,7 @@ def _process_table_schema(
                 info = attrs.evolve(info, numeric_precision=numeric_precision)
 
             elif issubclass(type_cls, Decimal):
-                items = info.data_type[8:].rstrip(")").split(",")
+                items = raw_data_type[8:].rstrip(")").split(",")
                 numeric_precision, numeric_scale = int(items[0]), int(items[1])
                 info = attrs.evolve(
                     info,

From c92956d38930fde42ce795d72803a916b44cd5ab Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 2 Jan 2024 16:43:07 -0700
Subject: [PATCH 62/99] fix typo -> ignored_columns2=self.ignored_columns2

---
 data_diff/hashdiff_tables.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 3fb53dd96..6a7fe4a32 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -233,7 +233,7 @@ def _bisect_and_diff_segments(
                     columns1=table1.relevant_columns,
                     columns2=table2.relevant_columns,
                     ignored_columns1=self.ignored_columns1,
-                    ignored_columns2=self.ignored_columns1,
+                    ignored_columns2=self.ignored_columns2,
                 )
             )
 

From 8bfbce13d0733febd9bfa6ebdcced99902588e05 Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Thu, 4 Jan 2024 00:25:19 +1100
Subject: [PATCH 63/99] Fix redshift schema ingest

---
 data_diff/databases/redshift.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index be9ec0fb0..d7bcd876b 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -181,7 +181,7 @@ def _normalize_schema_info(self, rows: Iterable[Tuple[Any]]) -> Dict[str, RawCol
 
             schema_dict[col_name] = RawColumnInfo(
                 column_name=col_name,
-                data_type=col_name,
+                data_type=base_type,
                 datetime_precision=None,
                 numeric_precision=precision,
                 numeric_scale=scale,

From 26485d729917882350f700a30dadd6f937f3dc29 Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Thu, 4 Jan 2024 02:01:40 +1100
Subject: [PATCH 64/99] Fix databricks schema handling

---
 data_diff/databases/databricks.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index b867d90df..efd35ea1a 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -187,7 +187,7 @@ def _process_table_schema(
         resulted_rows = []
         for info in col_infos:
             raw_data_type = info.data_type
-            row_type = "DECIMAL" if info.data_type.startswith("DECIMAL") else info.data_type
+            row_type = info.data_type.split("(")[0]
             info = attrs.evolve(info, data_type=row_type)
             type_cls = self.dialect.TYPE_CLASSES.get(row_type, UnknownColType)
 

From 530a1f6f05d911357f7cfced1231e8c686706eb8 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Wed, 3 Jan 2024 20:57:39 +0100
Subject: [PATCH 65/99] Group rows by all columns of composite PKs

---
 data_diff/hashdiff_tables.py | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 6a7fe4a32..295089654 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -23,7 +23,7 @@
 
 # Just for local readability: TODO: later switch to real type declarations of these.
 _Op = Literal["+", "-"]
-_PK = Any
+_PK = Sequence[Any]
 _Row = Tuple[Any]
 
 
@@ -34,6 +34,8 @@ def diff_sets(
     json_cols: dict = None,
     columns1: Sequence[str],
     columns2: Sequence[str],
+    key_columns1: Sequence[str],
+    key_columns2: Sequence[str],
     ignored_columns1: Collection[str],
     ignored_columns2: Collection[str],
 ) -> Iterator:
@@ -41,17 +43,18 @@ def diff_sets(
     sa: Set[_Row] = {tuple(val for col, val in safezip(columns1, row) if col not in ignored_columns1) for row in a}
     sb: Set[_Row] = {tuple(val for col, val in safezip(columns2, row) if col not in ignored_columns2) for row in b}
 
-    # The first item is always the key (see TableDiffer.relevant_columns)
-    # TODO update when we add compound keys to hashdiff
+    # The first items are always the PK (see TableSegment.relevant_columns)
     diffs_by_pks: Dict[_PK, List[Tuple[_Op, _Row]]] = defaultdict(list)
     for row in a:
+        pk: _PK = tuple(val for col, val in zip(key_columns1, row))
         cutrow: _Row = tuple(val for col, val in zip(columns1, row) if col not in ignored_columns1)
         if cutrow not in sb:
-            diffs_by_pks[row[0]].append(("-", row))
+            diffs_by_pks[pk].append(("-", row))
     for row in b:
+        pk: _PK = tuple(val for col, val in zip(key_columns2, row))
         cutrow: _Row = tuple(val for col, val in zip(columns2, row) if col not in ignored_columns2)
         if cutrow not in sa:
-            diffs_by_pks[row[0]].append(("+", row))
+            diffs_by_pks[pk].append(("+", row))
 
     warned_diff_cols = set()
     for diffs in (diffs_by_pks[pk] for pk in sorted(diffs_by_pks)):
@@ -232,6 +235,8 @@ def _bisect_and_diff_segments(
                     json_cols=json_cols,
                     columns1=table1.relevant_columns,
                     columns2=table2.relevant_columns,
+                    key_columns1=table1.key_columns,
+                    key_columns2=table2.key_columns,
                     ignored_columns1=self.ignored_columns1,
                     ignored_columns2=self.ignored_columns2,
                 )

From 8d1388a0c884fe5519a245d20a920d9141b31935 Mon Sep 17 00:00:00 2001
From: vvkh <vvkh@users.noreply.github.com>
Date: Wed, 3 Jan 2024 20:01:10 +0000
Subject: [PATCH 66/99] style fixes by ruff

---
 data_diff/databases/bigquery.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 54446980c..7caa14a13 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -123,17 +123,17 @@ def parse_type(self, table_path: DbPath, info: RawColumnInfo) -> ColType:
         if m:
             precision = int(m.group(3)) if m.group(3) else None
             scale = int(m.group(4)) if m.group(4) else None
-            
+
             if scale is not None:
-              # NUMERIC(..., scale) — scale is set explicitly
-              effective_precision = scale
+                # NUMERIC(..., scale) — scale is set explicitly
+                effective_precision = scale
             elif precision is not None:
-              # NUMERIC(...) — scale is missing but precision is set
-              # effectively the same as NUMERIC(..., 0)
-              effective_precision = 0
+                # NUMERIC(...) — scale is missing but precision is set
+                # effectively the same as NUMERIC(..., 0)
+                effective_precision = 0
             else:
-              # NUMERIC → default scale is 9
-              effective_precision = 9
+                # NUMERIC → default scale is 9
+                effective_precision = 9
             col_type = Decimal(precision=effective_precision)
             return col_type
 

From af36b663e1a06f1d78e3bf457b66a62f94ca6fcf Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sung@datafold.com>
Date: Thu, 4 Jan 2024 10:44:34 -0800
Subject: [PATCH 67/99] resync

---
 data_diff/databases/base.py | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 8beb00ff8..604bb04ae 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -922,6 +922,12 @@ class Database(abc.ABC):
     is_closed: bool = False
     _dialect: BaseDialect = None
 
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.close()
+
     @property
     def name(self):
         return type(self).__name__
@@ -1164,9 +1170,8 @@ def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> Que
         return apply_query(callback, sql_code)
 
     def close(self):
-        "Close connection(s) to the database instance. Querying will stop functioning."
+        """Close connection(s) to the database instance. Querying will stop functioning."""
         self.is_closed = True
-        return super().close()
 
     @property
     def dialect(self) -> BaseDialect:
@@ -1237,6 +1242,8 @@ def create_connection(self):
     def close(self):
         super().close()
         self._queue.shutdown()
+        if hasattr(self.thread_local, "conn"):
+            self.thread_local.conn.close()
 
     @property
     def is_autocommit(self) -> bool:
@@ -1263,4 +1270,4 @@ def is_autocommit(self) -> bool:
 DEFAULT_DATETIME_PRECISION = 6
 DEFAULT_NUMERIC_PRECISION = 24
 
-TIMESTAMP_PRECISION_POS = 20  # len("2022-06-03 12:24:35.") == 20
+TIMESTAMP_PRECISION_POS = 20  # len("2022-06-03 12:24:35.") == 20
\ No newline at end of file

From d05de0f3fb36c7ff1e303fc3e7be7bc1dc263e48 Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sung@datafold.com>
Date: Thu, 4 Jan 2024 10:45:05 -0800
Subject: [PATCH 68/99] Revert "resync"

This reverts commit af36b663e1a06f1d78e3bf457b66a62f94ca6fcf.
---
 data_diff/databases/base.py | 13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 604bb04ae..8beb00ff8 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -922,12 +922,6 @@ class Database(abc.ABC):
     is_closed: bool = False
     _dialect: BaseDialect = None
 
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exc_type, exc_value, traceback):
-        self.close()
-
     @property
     def name(self):
         return type(self).__name__
@@ -1170,8 +1164,9 @@ def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> Que
         return apply_query(callback, sql_code)
 
     def close(self):
-        """Close connection(s) to the database instance. Querying will stop functioning."""
+        "Close connection(s) to the database instance. Querying will stop functioning."
         self.is_closed = True
+        return super().close()
 
     @property
     def dialect(self) -> BaseDialect:
@@ -1242,8 +1237,6 @@ def create_connection(self):
     def close(self):
         super().close()
         self._queue.shutdown()
-        if hasattr(self.thread_local, "conn"):
-            self.thread_local.conn.close()
 
     @property
     def is_autocommit(self) -> bool:
@@ -1270,4 +1263,4 @@ def is_autocommit(self) -> bool:
 DEFAULT_DATETIME_PRECISION = 6
 DEFAULT_NUMERIC_PRECISION = 24
 
-TIMESTAMP_PRECISION_POS = 20  # len("2022-06-03 12:24:35.") == 20
\ No newline at end of file
+TIMESTAMP_PRECISION_POS = 20  # len("2022-06-03 12:24:35.") == 20

From d5a4d127637e6f241cb8823467c5cd157a63b73c Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Sat, 6 Jan 2024 04:11:10 +1300
Subject: [PATCH 69/99] Update README to be ergonomic and excite new users
 (#816)

* update draft

* elliot's edits

* remove kafka

* less awkward than the center

* elliot's edits

* added docs link

* Scope the utility to single players

* swapped order

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
Co-authored-by: elliotgunn <elliot.j.gunn@gmail.com>
---
 README.md | 146 ++++++++++++++++++++++++++++++++----------------------
 1 file changed, 86 insertions(+), 60 deletions(-)

diff --git a/README.md b/README.md
index 1a0f1ba99..3c6e77f22 100644
--- a/README.md
+++ b/README.md
@@ -9,79 +9,61 @@ data-diff: Compare datasets fast, within or across SQL databases
 </h2>
 <br>
 
-> [Make sure to join us at our virtual hands-on lab series where our team walks through live how to get set-up with it!](https://www.datafold.com/virtual-hands-on-lab)
+> [Join our live virtual lab series to learn how to set it up!](https://www.datafold.com/virtual-hands-on-lab)
 
-# Use Cases
+# What's a Data Diff?
+A data diff is the value-level comparison between two tables—used to identify critical changes to your data and guarantee data quality.
+
+There is a lot you can do with data-diff: you can test SQL code by comparing development or staging environment data to production, or compare source and target data to identify discrepancies when moving data between databases.
 
-## Data Migration & Replication Testing
-Compare source to target and check for discrepancies when moving data between systems:
-- Migrating to a new data warehouse (e.g., Oracle > Snowflake)
-- Converting SQL to a new transformation framework (e.g., stored procedures > dbt)
-- Continuously replicating data from an OLTP DB to OLAP DWH (e.g., MySQL > Redshift)
+# Use Cases
 
+### Data Migration & Replication Testing
+data-diff is a powerful tool for comparing data when you're moving it between systems. Use it to ensure data accuracy and identify discrepancies during tasks like:
+- **Migrating** to a new data warehouse (e.g., Oracle -> Snowflake)
+- **Converting SQL** to a new transformation framework (e.g., stored procedures -> dbt)
+- Continuously **replicating data** from an OLTP database to OLAP data warehouse (e.g., MySQL -> Redshift)
 
-## Data Development Testing
-Test SQL code and preview changes by comparing development/staging environment data to production:
-1. Make a change to some SQL code
+### Data Development Testing 
+When developing SQL code, data-diff helps you validate and preview changes by comparing data between development/staging environments and production. Here's how it works:
+1. Make a change to your SQL code
 2. Run the SQL code to create a new dataset
-3. Compare the dataset with its production version or another iteration
+3. Compare this dataset with its production version or other iterations
 
+# dbt Integration
   <p align="left">
   <img alt="dbt" src="https://seeklogo.com/images/D/dbt-logo-E4B0ED72A2-seeklogo.com.png" width="10%" />
-  </p>
-
-<details>
-<summary> data-diff integrates with dbt Core to seamlessly compare local development to production datasets
+  </p> 
 
- </summary>
+data-diff integrates with [dbt Core](https://github.com/dbt-labs/dbt-core) to seamlessly compare local development to production datasets.
 
-![data-development-testing](docs/development_testing.png)
+Learn more about how data-diff works with dbt:
+* Read our docs to get started with [data-diff & dbt](https://docs.datafold.com/development_testing/cli) or :eyes: **watch the [4-min demo video](https://www.loom.com/share/ad3df969ba6b4298939efb2fbcc14cde)**
+* dbt Cloud users should check out [Datafold's out-of-the-box deployment testing integration](https://www.datafold.com/data-deployment-testing)
+* Get support from the dbt Community Slack in [#tools-datafold](https://getdbt.slack.com/archives/C03D25A92UU)
 
-</details>
 
-> [dbt Cloud users should check out Datafold's out-of-the-box deployment testing integration](https://www.datafold.com/data-deployment-testing)
+# Getting Started
 
-:eyes: **Watch [4-min demo video](https://www.loom.com/share/ad3df969ba6b4298939efb2fbcc14cde)**
+### ⚡ Validating dbt model changes between dev and prod
+Looking to use data-diff in dbt development? 
 
-**[Get started with data-diff & dbt](https://docs.datafold.com/development_testing/open_source)**
-
-Reach out on the dbt Slack in [#tools-datafold](https://getdbt.slack.com/archives/C03D25A92UU) for advice and support
-
-
-# How it works
+Development testing with Datafold enables you to see the impact of dbt code changes on data as you write the code, whether in your IDE or CLI. 
 
-When comparing the data, `data-diff` utilizes the resources of the underlying databases as much as possible. It has two primary modes of comparison:
+ Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/cli) to get started with a development testing workflow!
 
-## `joindiff`
-- Recommended for comparing data within the same database
-- Uses the outer join operation to diff the rows as efficiently as possible within the same database
-- Fully relies on the underlying database engine for computation
-- Requires both datasets to be queryable with a single SQL query
-- Time complexity approximates JOIN operation and is largely independent of the number of differences in the dataset
+### 🔀 Compare data tables between databases
+1. Install `data-diff` with adapters
 
-## `hashdiff`
-- Recommended for comparing datasets across different databases
-- Can also be helpful in diffing very large tables with few expected differences within the same database
-- Employs a divide-and-conquer algorithm based on hashing and binary search
-- Can diff data across distinct database engines, e.g., PostgreSQL <> Snowflake
-- Time complexity approximates COUNT(*) operation when there are few differences
-- Performance degrades when datasets have a large number of differences
-
-More information about the algorithm and performance considerations can be found [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md)
-
-# Get started
-
-## Validating dbt model changes between dev and prod
-⚡ Looking to use `data-diff` in dbt development? Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/how_it_works) to get started!
-
-## Compare data tables between databases
-🔀 To compare data between databases, install `data-diff` with specific database adapters, e.g.:
+To compare data between databases, install `data-diff` with specific database adapters. For example, install it for PostgreSQL and Snowflake like this:
 
 ```
 pip install data-diff 'data-diff[postgresql,snowflake]' -U
 ```
 
-Run `data-diff` with connection URIs. In the following example, we compare tables between PostgreSQL and Snowflake using the hashdiff algorithm:
+2. Run `data-diff` with connection URIs
+
+Then, we compare tables between PostgreSQL and Snowflake using the hashdiff algorithm:
 
 ```bash
 data-diff \
@@ -93,8 +75,9 @@ data-diff \
   -c <columns to compare> \
   -w <filter condition>
 ```
+3. Set up your configuration 
 
-Run `data-diff` with a `toml` configuration file. In the following example, we compare tables between MotherDuck(hosted DuckDB) and Snowflake using the hashdiff algorithm:
+You can use a `toml` configuration file to run your `data-diff` job. In this example, we compare tables between MotherDuck (hosted DuckDB) and Snowflake using the hashdiff algorithm:
 
 ```toml
 ## DATABASE CONNECTION ##
@@ -103,7 +86,6 @@ Run `data-diff` with a `toml` configuration file. In the following example, we c
   # filepath = "datafold_demo.duckdb" # local duckdb file example
   # filepath = "md:" # default motherduck connection example
   filepath = "md:datafold_demo?motherduck_token=${motherduck_token}" # API token recommended for motherduck connection
-  database = "datafold_demo"
 
 [database.snowflake_connection]
   driver = "snowflake"
@@ -132,8 +114,12 @@ Run `data-diff` with a `toml` configuration file. In the following example, we c
 
   verbose = false
 ```
+4. Run your `data-diff` job
+
+Make sure to export relevant environment variables as needed. For example, we compare data based on the earlier configuration:
 
 ```bash
+
 # export relevant environment variables, example below
 export motherduck_token=<MOTHERDUCK_TOKEN>
 
@@ -148,11 +134,13 @@ data-diff --conf datadiff.toml \
 + 1, returned
 ```
 
-Check out [documentation](https://docs.datafold.com/reference/open_source/cli) for the full command reference.
+5. Review the output
 
+After running your data-diff job, review the output to identify and analyze differences in your data.
 
-# Supported databases
+Check out [documentation](https://docs.datafold.com/reference/open_source/cli) for the full command reference.
 
+# Supported databases
 
 | Database      | Status | Connection string                                                                                                                   |
 |---------------|-------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
@@ -161,8 +149,8 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Snowflake     |  🟢     | `"snowflake://<user>[:<password>]@<account>/<database>/<SCHEMA>?warehouse=<WAREHOUSE>&role=<role>[&authenticator=externalbrowser]"` |
 | BigQuery      |  🟢     | `bigquery://<project>/<dataset>`                                                                                                    |
 | Redshift      |  🟢     | `redshift://<username>:<password>@<hostname>:5439/<database>`                                                                       |
-| DuckDB        |  🟢   | `duckdb://<dbname>@<filepath>`                                                                                          |
-| MotherDuck        |  🟢   | `duckdb://<dbname>@<filepath>`                                                                                                   |
+| DuckDB        |  🟢   | `duckdb://<filepath>`                                                                                          |
+| MotherDuck        |  🟢   | `duckdb://<filepath>`                                                                                                   |
 | Oracle        |  🟡   | `oracle://<username>:<password>@<hostname>/servive_or_sid`                                                                          |
 | Presto        |  🟡   | `presto://<username>:<password>@<hostname>:8080/<database>`                                                                         |
 | Databricks    |  🟡   | `databricks://<http_path>:<access_token>@<server_hostname>/<catalog>/<schema>`                                                      |
@@ -172,8 +160,7 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | ElasticSearch |  📝    |                                                                                                                                     |
 | Planetscale   |  📝    |                                                                                                                                     |
 | Pinot         |  📝    |                                                                                                                                     |
-| Druid         |  📝    |                                                                                                                                     |
-| Kafka         |  📝    |                                                                                                                                     |
+| Druid         |  📝    |                                                                                                                                     |                                                                                                                                  |
 | SQLite        |  📝    |                                                                                                                                     |
 
 * 🟢: Implemented and thoroughly tested.
@@ -189,9 +176,48 @@ Your database not listed here?
 
 <br>
 
+# How it works
+
+`data-diff` efficiently compares data using two modes:
+
+**joindiff**: Ideal for comparing data within the same database, utilizing outer joins for efficient row comparisons. It relies on the database engine for computation and has consistent performance.
+
+**hashdiff**: Recommended for comparing datasets across different databases or large tables with minimal differences. It uses hashing and binary search, capable of diffing data across distinct database engines.
+
+<details>
+<summary>Click here to learn more about joindiff and hashdiff</summary>
+
+### `joindiff`
+* Recommended for comparing data within the same database
+* Uses the outer join operation to diff the rows as efficiently as possible within the same database
+* Fully relies on the underlying database engine for computation
+* Requires both datasets to be queryable with a single SQL query
+* Time complexity approximates JOIN operation and is largely independent of the number of differences in the dataset
+
+### `hashdiff`:
+* Recommended for comparing datasets across different databases
+* Can also be helpful in diffing very large tables with few expected differences within the same database
+* Employs a divide-and-conquer algorithm based on hashing and binary search
+* Can diff data across distinct database engines, e.g., PostgreSQL <> Snowflake
+* Time complexity approximates COUNT(*) operation when there are few differences
+* Performance degrades when datasets have a large number of differences
+
+</details>  
+<br>
+
+For detailed algorithm and performance insights, explore [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md), or head to our docs to [learn more about how Datafold diffs data](https://docs.datafold.com/data_diff/how-datafold-diffs-data). 
+
+
+# data-diff OSS & Datafold Cloud
+data-diff is an open source utility for running stateless diffs on your local computer for a great single player experience.
+
+Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a company-wide experience to both supercharge your data diffing CLI experience (ex: data-diff --dbt --cloud) and run diffs manually in the UI. This includes [column-level lineage](https://www.datafold.com/column-level-lineage), [CI testing](https://docs.datafold.com/deployment_testing/how_it_works/), and diff history.
+
 ## Contributors
 
-We thank everyone who contributed so far!
+We thank everyone who contributed so far! 
+
+We'd love to see your face here: [Contributing Instructions](CONTRIBUTING.md)
 
 <a href="https://github.com/datafold/data-diff/graphs/contributors">
   <img src="https://contributors-img.web.app/image?repo=datafold/data-diff" />

From ce09a5c43bb3ee2264982da5d9ff8b4bfce5cdfa Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:33:47 +0100
Subject: [PATCH 70/99] Annotate constructors which always return None

---
 data_diff/__main__.py             |  2 +-
 data_diff/abcs/database_types.py  |  2 +-
 data_diff/cloud/datafold_api.py   |  2 +-
 data_diff/databases/_connect.py   |  2 +-
 data_diff/databases/base.py       |  2 +-
 data_diff/databases/bigquery.py   |  2 +-
 data_diff/databases/clickhouse.py |  2 +-
 data_diff/databases/databricks.py |  2 +-
 data_diff/databases/duckdb.py     |  2 +-
 data_diff/databases/mssql.py      |  2 +-
 data_diff/databases/mysql.py      |  2 +-
 data_diff/databases/oracle.py     |  2 +-
 data_diff/databases/postgresql.py |  2 +-
 data_diff/databases/presto.py     |  2 +-
 data_diff/databases/snowflake.py  |  2 +-
 data_diff/databases/trino.py      |  2 +-
 data_diff/databases/vertica.py    |  2 +-
 data_diff/hashdiff_tables.py      |  2 +-
 data_diff/lexicographic_space.py  |  4 ++--
 data_diff/queries/ast_classes.py  |  2 +-
 data_diff/table_segment.py        |  2 +-
 data_diff/thread_utils.py         |  4 ++--
 data_diff/utils.py                |  6 +++---
 tests/test_database_types.py      | 14 +++++++-------
 24 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/data_diff/__main__.py b/data_diff/__main__.py
index c4e698f5c..0fe510bce 100644
--- a/data_diff/__main__.py
+++ b/data_diff/__main__.py
@@ -103,7 +103,7 @@ def diff_schemas(table1, table2, schema1, schema2, columns):
 
 
 class MyHelpFormatter(click.HelpFormatter):
-    def __init__(self, **kwargs):
+    def __init__(self, **kwargs) -> None:
         super().__init__(self, **kwargs)
         self.indent_increment = 6
 
diff --git a/data_diff/abcs/database_types.py b/data_diff/abcs/database_types.py
index e5aa5fab5..1c40883d5 100644
--- a/data_diff/abcs/database_types.py
+++ b/data_diff/abcs/database_types.py
@@ -290,7 +290,7 @@ class Integer(NumericType, IKey):
     precision: int = 0
     python_type: type = int
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         assert self.precision == 0
 
 
diff --git a/data_diff/cloud/datafold_api.py b/data_diff/cloud/datafold_api.py
index 3ec637a02..2bba52431 100644
--- a/data_diff/cloud/datafold_api.py
+++ b/data_diff/cloud/datafold_api.py
@@ -185,7 +185,7 @@ class DatafoldAPI:
     host: str = "https://app.datafold.com"
     timeout: int = 30
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         self.host = self.host.rstrip("/")
         self.headers = {
             "Authorization": f"Key {self.api_key}",
diff --git a/data_diff/databases/_connect.py b/data_diff/databases/_connect.py
index 1e34ef62b..df63c78bc 100644
--- a/data_diff/databases/_connect.py
+++ b/data_diff/databases/_connect.py
@@ -100,7 +100,7 @@ class Connect:
     database_by_scheme: Dict[str, Database]
     conn_cache: MutableMapping[Hashable, Database]
 
-    def __init__(self, database_by_scheme: Dict[str, Database] = DATABASE_BY_SCHEME):
+    def __init__(self, database_by_scheme: Dict[str, Database] = DATABASE_BY_SCHEME) -> None:
         super().__init__()
         self.database_by_scheme = database_by_scheme
         self.conn_cache = weakref.WeakValueDictionary()
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 8beb00ff8..2fea76d31 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -1209,7 +1209,7 @@ class ThreadedDatabase(Database):
     _queue: Optional[ThreadPoolExecutor] = None
     thread_local: threading.local = attrs.field(factory=threading.local)
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         self._queue = ThreadPoolExecutor(self.thread_count, initializer=self.set_conn)
         logger.info(f"[{self.name}] Starting a threadpool, size={self.thread_count}.")
 
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 7caa14a13..2216bf412 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -212,7 +212,7 @@ class BigQuery(Database):
     dataset: str
     _client: Any
 
-    def __init__(self, project, *, dataset, bigquery_credentials=None, **kw):
+    def __init__(self, project, *, dataset, bigquery_credentials=None, **kw) -> None:
         super().__init__()
         credentials = bigquery_credentials
         bigquery = import_bigquery()
diff --git a/data_diff/databases/clickhouse.py b/data_diff/databases/clickhouse.py
index 7bbc156f6..43b69b3fa 100644
--- a/data_diff/databases/clickhouse.py
+++ b/data_diff/databases/clickhouse.py
@@ -175,7 +175,7 @@ class Clickhouse(ThreadedDatabase):
 
     _args: Dict[str, Any]
 
-    def __init__(self, *, thread_count: int, **kw):
+    def __init__(self, *, thread_count: int, **kw) -> None:
         super().__init__(thread_count=thread_count)
 
         self._args = kw
diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index efd35ea1a..dd83a95c5 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -118,7 +118,7 @@ class Databricks(ThreadedDatabase):
     catalog: str
     _args: Dict[str, Any]
 
-    def __init__(self, *, thread_count, **kw):
+    def __init__(self, *, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
         logging.getLogger("databricks.sql").setLevel(logging.WARNING)
 
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index 48a44ffc1..4cdacde87 100644
--- a/data_diff/databases/duckdb.py
+++ b/data_diff/databases/duckdb.py
@@ -126,7 +126,7 @@ class DuckDB(Database):
     _args: Dict[str, Any] = attrs.field(init=False)
     _conn: Any = attrs.field(init=False)
 
-    def __init__(self, **kw):
+    def __init__(self, **kw) -> None:
         super().__init__()
         self._args = kw
         self._conn = self.create_connection()
diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index c54446105..c9ec09bfe 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -168,7 +168,7 @@ class MsSQL(ThreadedDatabase):
     _args: Dict[str, Any]
     _mssql: Any
 
-    def __init__(self, host, port, user, password, *, database, thread_count, **kw):
+    def __init__(self, host, port, user, password, *, database, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
 
         args = dict(server=host, port=port, database=database, user=user, password=password, **kw)
diff --git a/data_diff/databases/mysql.py b/data_diff/databases/mysql.py
index 2b1e810fe..941673b04 100644
--- a/data_diff/databases/mysql.py
+++ b/data_diff/databases/mysql.py
@@ -129,7 +129,7 @@ class MySQL(ThreadedDatabase):
 
     _args: Dict[str, Any]
 
-    def __init__(self, *, thread_count, **kw):
+    def __init__(self, *, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
         self._args = kw
 
diff --git a/data_diff/databases/oracle.py b/data_diff/databases/oracle.py
index 2f6537be1..36d154a06 100644
--- a/data_diff/databases/oracle.py
+++ b/data_diff/databases/oracle.py
@@ -164,7 +164,7 @@ class Oracle(ThreadedDatabase):
     kwargs: Dict[str, Any]
     _oracle: Any
 
-    def __init__(self, *, host, database, thread_count, **kw):
+    def __init__(self, *, host, database, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
         self.kwargs = dict(dsn=f"{host}/{database}" if database else host, **kw)
         self.default_schema = kw.get("user").upper()
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 93e0dc2f6..1ec34f4ce 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -163,7 +163,7 @@ class PostgreSQL(ThreadedDatabase):
     _args: Dict[str, Any]
     _conn: Any
 
-    def __init__(self, *, thread_count, **kw):
+    def __init__(self, *, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
         self._args = kw
         self.default_schema = "public"
diff --git a/data_diff/databases/presto.py b/data_diff/databases/presto.py
index 034ac99fd..42e28056f 100644
--- a/data_diff/databases/presto.py
+++ b/data_diff/databases/presto.py
@@ -152,7 +152,7 @@ class Presto(Database):
 
     _conn: Any
 
-    def __init__(self, **kw):
+    def __init__(self, **kw) -> None:
         super().__init__()
         self.default_schema = "public"
         prestodb = import_presto()
diff --git a/data_diff/databases/snowflake.py b/data_diff/databases/snowflake.py
index 1b70085a5..823ae5b29 100644
--- a/data_diff/databases/snowflake.py
+++ b/data_diff/databases/snowflake.py
@@ -104,7 +104,7 @@ class Snowflake(Database):
 
     _conn: Any
 
-    def __init__(self, *, schema: str, key: Optional[str] = None, key_content: Optional[str] = None, **kw):
+    def __init__(self, *, schema: str, key: Optional[str] = None, key_content: Optional[str] = None, **kw) -> None:
         super().__init__()
         snowflake, serialization, default_backend = import_snowflake()
         logging.getLogger("snowflake.connector").setLevel(logging.WARNING)
diff --git a/data_diff/databases/trino.py b/data_diff/databases/trino.py
index b76ba74bb..5a432ee52 100644
--- a/data_diff/databases/trino.py
+++ b/data_diff/databases/trino.py
@@ -40,7 +40,7 @@ class Trino(presto.Presto):
 
     _conn: Any
 
-    def __init__(self, **kw):
+    def __init__(self, **kw) -> None:
         super().__init__()
         trino = import_trino()
 
diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index 27d017bdb..f997601d4 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -137,7 +137,7 @@ class Vertica(ThreadedDatabase):
 
     _args: Dict[str, Any]
 
-    def __init__(self, *, thread_count, **kw):
+    def __init__(self, *, thread_count, **kw) -> None:
         super().__init__(thread_count=thread_count)
         self._args = kw
         self._args["AUTOCOMMIT"] = False
diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 295089654..0984d9f1a 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -96,7 +96,7 @@ class HashDiffer(TableDiffer):
 
     stats: dict = attrs.field(factory=dict)
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         # Validate options
         if self.bisection_factor >= self.bisection_threshold:
             raise ValueError("Incorrect param values (bisection factor must be lower than threshold)")
diff --git a/data_diff/lexicographic_space.py b/data_diff/lexicographic_space.py
index b7d88e369..25d5d6470 100644
--- a/data_diff/lexicographic_space.py
+++ b/data_diff/lexicographic_space.py
@@ -66,7 +66,7 @@ class LexicographicSpace:
     All elements must be of the same length as the number of dimensions. (no rpadding)
     """
 
-    def __init__(self, dims: Vector):
+    def __init__(self, dims: Vector) -> None:
         super().__init__()
         self.dims = dims
 
@@ -124,7 +124,7 @@ class BoundedLexicographicSpace:
     i.e. a space resticted by a "bounding-box" between two arbitrary points.
     """
 
-    def __init__(self, min_bound: Vector, max_bound: Vector):
+    def __init__(self, min_bound: Vector, max_bound: Vector) -> None:
         super().__init__()
 
         dims = tuple(mx - mn for mn, mx in safezip(min_bound, max_bound))
diff --git a/data_diff/queries/ast_classes.py b/data_diff/queries/ast_classes.py
index 3bf14fd7c..348a58ca8 100644
--- a/data_diff/queries/ast_classes.py
+++ b/data_diff/queries/ast_classes.py
@@ -523,7 +523,7 @@ class GroupBy(ExprNode, ITable, Root):
     values: Optional[Sequence[Expr]] = None
     having_exprs: Optional[Sequence[Expr]] = None
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         assert self.keys or self.values
 
     def having(self, *exprs) -> Self:
diff --git a/data_diff/table_segment.py b/data_diff/table_segment.py
index 924271bac..4e9f41b10 100644
--- a/data_diff/table_segment.py
+++ b/data_diff/table_segment.py
@@ -126,7 +126,7 @@ class TableSegment:
     case_sensitive: Optional[bool] = True
     _schema: Optional[Schema] = None
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         if not self.update_column and (self.min_update or self.max_update):
             raise ValueError("Error: the min_update/max_update feature requires 'update_column' to be set.")
 
diff --git a/data_diff/thread_utils.py b/data_diff/thread_utils.py
index ba292ef54..b3d975904 100644
--- a/data_diff/thread_utils.py
+++ b/data_diff/thread_utils.py
@@ -34,7 +34,7 @@ class PriorityThreadPoolExecutor(ThreadPoolExecutor):
     XXX WARNING: Might break in future versions of Python
     """
 
-    def __init__(self, *args):
+    def __init__(self, *args) -> None:
         super().__init__(*args)
         self._work_queue = AutoPriorityQueue()
 
@@ -58,7 +58,7 @@ class ThreadedYielder(Iterable):
     _exception: Optional[None]
     yield_list: bool
 
-    def __init__(self, max_workers: Optional[int] = None, yield_list: bool = False):
+    def __init__(self, max_workers: Optional[int] = None, yield_list: bool = False) -> None:
         super().__init__()
         self._pool = PriorityThreadPoolExecutor(max_workers)
         self._futures = deque()
diff --git a/data_diff/utils.py b/data_diff/utils.py
index e16110e11..a996e8e9d 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -80,7 +80,7 @@ def new(self, initial=()) -> Self:
 
 
 class CaseInsensitiveDict(CaseAwareMapping):
-    def __init__(self, initial):
+    def __init__(self, initial) -> None:
         super().__init__()
         self._dict = {k.lower(): (k, v) for k, v in dict(initial).items()}
 
@@ -241,7 +241,7 @@ class ArithAlphanumeric(ArithString):
     _str: str
     _max_len: Optional[int] = None
 
-    def __attrs_post_init__(self):
+    def __attrs_post_init__(self) -> None:
         if self._str is None:
             raise ValueError("Alphanum string cannot be None")
         if self._max_len and len(self._str) > self._max_len:
@@ -540,7 +540,7 @@ class LogStatusHandler(logging.Handler):
     This log handler can be used to update a rich.status every time a log is emitted.
     """
 
-    def __init__(self):
+    def __init__(self) -> None:
         super().__init__()
         self.status = Status("")
         self.prefix = ""
diff --git a/tests/test_database_types.py b/tests/test_database_types.py
index e97ca4844..11b01593e 100644
--- a/tests/test_database_types.py
+++ b/tests/test_database_types.py
@@ -366,7 +366,7 @@ class PaginatedTable:
     # much memory.
     RECORDS_PER_BATCH = 1000000
 
-    def __init__(self, table_path, conn):
+    def __init__(self, table_path, conn) -> None:
         super().__init__()
         self.table_path = table_path
         self.conn = conn
@@ -398,7 +398,7 @@ class DateTimeFaker:
         datetime.fromisoformat("2022-06-01 15:10:05.009900"),
     ]
 
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
@@ -414,7 +414,7 @@ def __len__(self):
 class IntFaker:
     MANUAL_FAKES = [127, -3, -9, 37, 15, 0]
 
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
@@ -430,7 +430,7 @@ def __len__(self):
 class BooleanFaker:
     MANUAL_FAKES = [False, True, True, False]
 
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
@@ -461,7 +461,7 @@ class FloatFaker:
         3.141592653589793,
     ]
 
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
@@ -475,7 +475,7 @@ def __len__(self):
 
 
 class UUID_Faker:
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
@@ -491,7 +491,7 @@ class JsonFaker:
         '{"keyText": "text", "keyInt": 3, "keyFloat": 5.4445, "keyBoolean": true}',
     ]
 
-    def __init__(self, max):
+    def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 

From ec6786c31dd9691ed3f71c5b3fbe616dc6695859 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:35:42 +0100
Subject: [PATCH 71/99] Annotate magic methods with predictable result types

---
 data_diff/databases/base.py      |  2 +-
 data_diff/lexicographic_space.py |  4 ++--
 data_diff/queries/base.py        |  2 +-
 data_diff/utils.py               | 30 +++++++++++++++---------------
 tests/test_database_types.py     | 12 ++++++------
 5 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 2fea76d31..e91f901e5 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -895,7 +895,7 @@ class QueryResult:
     def __iter__(self):
         return iter(self.rows)
 
-    def __len__(self):
+    def __len__(self) -> int:
         return len(self.rows)
 
     def __getitem__(self, i):
diff --git a/data_diff/lexicographic_space.py b/data_diff/lexicographic_space.py
index 25d5d6470..32fdde701 100644
--- a/data_diff/lexicographic_space.py
+++ b/data_diff/lexicographic_space.py
@@ -70,7 +70,7 @@ def __init__(self, dims: Vector) -> None:
         super().__init__()
         self.dims = dims
 
-    def __contains__(self, v: Vector):
+    def __contains__(self, v: Vector) -> bool:
         return all(0 <= i < d for i, d in safezip(v, self.dims))
 
     def add(self, v1: Vector, v2: Vector) -> Vector:
@@ -138,7 +138,7 @@ def __init__(self, min_bound: Vector, max_bound: Vector) -> None:
 
         self.uspace = LexicographicSpace(dims)
 
-    def __contains__(self, p: Vector):
+    def __contains__(self, p: Vector) -> bool:
         return all(mn <= i < mx for i, mn, mx in safezip(p, self.min_bound, self.max_bound))
 
     def to_uspace(self, v: Vector) -> Vector:
diff --git a/data_diff/queries/base.py b/data_diff/queries/base.py
index ca8953c40..7f7cd1de1 100644
--- a/data_diff/queries/base.py
+++ b/data_diff/queries/base.py
@@ -5,7 +5,7 @@
 
 @attrs.define(frozen=True)
 class _SKIP:
-    def __repr__(self):
+    def __repr__(self) -> str:
         return "SKIP"
 
 
diff --git a/data_diff/utils.py b/data_diff/utils.py
index a996e8e9d..4e2942dff 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -161,7 +161,7 @@ def range(self, other: "ArithUUID", count: int) -> List[Self]:
         checkpoints = split_space(self.uuid.int, other.uuid.int, count)
         return [attrs.evolve(self, uuid=i) for i in checkpoints]
 
-    def __int__(self):
+    def __int__(self) -> int:
         return self.uuid.int
 
     def __add__(self, other: int) -> Self:
@@ -255,16 +255,16 @@ def __attrs_post_init__(self) -> None:
     # def int(self):
     #     return alphanumToNumber(self._str, alphanums)
 
-    def __str__(self):
+    def __str__(self) -> str:
         s = self._str
         if self._max_len:
             s = s.rjust(self._max_len, alphanums[0])
         return s
 
-    def __len__(self):
+    def __len__(self) -> int:
         return len(self._str)
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return f'alphanum"{self._str}"'
 
     def __add__(self, other: "Union[ArithAlphanumeric, int]") -> Self:
@@ -289,17 +289,17 @@ def __sub__(self, other: "Union[ArithAlphanumeric, int]") -> float:
 
         return NotImplemented
 
-    def __ge__(self, other):
+    def __ge__(self, other) -> bool:
         if not isinstance(other, type(self)):
             return NotImplemented
         return self._str >= other._str
 
-    def __lt__(self, other):
+    def __lt__(self, other) -> bool:
         if not isinstance(other, type(self)):
             return NotImplemented
         return self._str < other._str
 
-    def __eq__(self, other):
+    def __eq__(self, other) -> bool:
         if not isinstance(other, type(self)):
             return NotImplemented
         return self._str == other._str
@@ -424,32 +424,32 @@ class Vector(tuple):
     Partial implementation: Only the needed functionality is implemented
     """
 
-    def __lt__(self, other: "Vector"):
+    def __lt__(self, other: "Vector") -> bool:
         if isinstance(other, Vector):
             return all(a < b for a, b in safezip(self, other))
         return NotImplemented
 
-    def __le__(self, other: "Vector"):
+    def __le__(self, other: "Vector") -> bool:
         if isinstance(other, Vector):
             return all(a <= b for a, b in safezip(self, other))
         return NotImplemented
 
-    def __gt__(self, other: "Vector"):
+    def __gt__(self, other: "Vector") -> bool:
         if isinstance(other, Vector):
             return all(a > b for a, b in safezip(self, other))
         return NotImplemented
 
-    def __ge__(self, other: "Vector"):
+    def __ge__(self, other: "Vector") -> bool:
         if isinstance(other, Vector):
             return all(a >= b for a, b in safezip(self, other))
         return NotImplemented
 
-    def __eq__(self, other: "Vector"):
+    def __eq__(self, other: "Vector") -> bool:
         if isinstance(other, Vector):
             return all(a == b for a, b in safezip(self, other))
         return NotImplemented
 
-    def __sub__(self, other: "Vector"):
+    def __sub__(self, other: "Vector") -> "Vector":
         if isinstance(other, Vector):
             return Vector((a - b) for a, b in safezip(self, other))
         raise NotImplementedError()
@@ -575,12 +575,12 @@ class UnknownMeta(type):
     def __instancecheck__(self, instance):
         return instance is Unknown
 
-    def __repr__(self):
+    def __repr__(self) -> str:
         return "Unknown"
 
 
 class Unknown(metaclass=UnknownMeta):
-    def __nonzero__(self):
+    def __bool__(self) -> bool:
         raise TypeError()
 
     def __new__(class_, *args, **kwargs):
diff --git a/tests/test_database_types.py b/tests/test_database_types.py
index 11b01593e..2ba7a1e8b 100644
--- a/tests/test_database_types.py
+++ b/tests/test_database_types.py
@@ -407,7 +407,7 @@ def __iter__(self):
         step = timedelta(seconds=3, microseconds=571)
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
 
-    def __len__(self):
+    def __len__(self) -> int:
         return self.max
 
 
@@ -423,7 +423,7 @@ def __iter__(self):
         step = 1
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
 
-    def __len__(self):
+    def __len__(self) -> int:
         return self.max
 
 
@@ -437,7 +437,7 @@ def __init__(self, max) -> None:
     def __iter__(self):
         return iter(self.MANUAL_FAKES[: self.max])
 
-    def __len__(self):
+    def __len__(self) -> int:
         return min(self.max, len(self.MANUAL_FAKES))
 
 
@@ -470,7 +470,7 @@ def __iter__(self):
         step = 0.00571
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
 
-    def __len__(self):
+    def __len__(self) -> int:
         return self.max
 
 
@@ -479,7 +479,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __len__(self):
+    def __len__(self) -> int:
         return self.max
 
     def __iter__(self):
@@ -498,7 +498,7 @@ def __init__(self, max) -> None:
     def __iter__(self):
         return iter(self.MANUAL_FAKES[: self.max])
 
-    def __len__(self):
+    def __len__(self) -> int:
         return min(self.max, len(self.MANUAL_FAKES))
 
 

From ad34a1db1a5a2608bd9e788c89e6f8fe70f36a55 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:43:04 +0100
Subject: [PATCH 72/99] Annotate simple iterators

---
 data_diff/databases/base.py  | 24 ++++++++++++++++++++----
 data_diff/diff_tables.py     |  4 ++--
 data_diff/schema.py          |  4 ++--
 data_diff/thread_utils.py    |  4 ++--
 tests/test_database_types.py | 16 +++++++++-------
 5 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index e91f901e5..7d1640868 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -5,7 +5,22 @@
 import math
 import sys
 import logging
-from typing import Any, Callable, ClassVar, Dict, Generator, Tuple, Optional, Sequence, Type, List, Union, TypeVar
+from typing import (
+    Any,
+    Callable,
+    ClassVar,
+    Dict,
+    Generator,
+    Iterator,
+    NewType,
+    Tuple,
+    Optional,
+    Sequence,
+    Type,
+    List,
+    Union,
+    TypeVar,
+)
 from functools import partial, wraps
 from concurrent.futures import ThreadPoolExecutor
 import threading
@@ -885,20 +900,21 @@ def optimizer_hints(self, hints: str) -> str:
 
 
 T = TypeVar("T", bound=BaseDialect)
+Row = Sequence[Any]
 
 
 @attrs.define(frozen=True)
 class QueryResult:
-    rows: list
+    rows: List[Row]
     columns: Optional[list] = None
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Row]:
         return iter(self.rows)
 
     def __len__(self) -> int:
         return len(self.rows)
 
-    def __getitem__(self, i):
+    def __getitem__(self, i) -> Row:
         return self.rows[i]
 
 
diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 5ec1f71b1..74376f639 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -6,7 +6,7 @@
 from enum import Enum
 from contextlib import contextmanager
 from operator import methodcaller
-from typing import Dict, Set, List, Tuple, Iterator, Optional, Union
+from typing import Any, Dict, Set, List, Tuple, Iterator, Optional, Union
 from concurrent.futures import ThreadPoolExecutor, as_completed
 
 import attrs
@@ -89,7 +89,7 @@ class DiffResultWrapper:
     stats: dict
     result_list: list = attrs.field(factory=list)
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Any]:
         yield from self.result_list
         for i in self.diff:
             self.result_list.append(i)
diff --git a/data_diff/schema.py b/data_diff/schema.py
index f04089355..d77e298b4 100644
--- a/data_diff/schema.py
+++ b/data_diff/schema.py
@@ -1,5 +1,5 @@
 import logging
-from typing import Any, Collection, Iterable, Optional
+from typing import Any, Collection, Iterator, Optional
 
 import attrs
 
@@ -28,7 +28,7 @@ class RawColumnInfo(Collection[Any]):
     collation_name: Optional[str] = None
 
     # It was a tuple once, so we keep it backward compatible temporarily, until remade to classes.
-    def __iter__(self) -> Iterable[Any]:
+    def __iter__(self) -> Iterator[Any]:
         return iter(
             (self.column_name, self.data_type, self.datetime_precision, self.numeric_precision, self.numeric_scale)
         )
diff --git a/data_diff/thread_utils.py b/data_diff/thread_utils.py
index b3d975904..1b451a48d 100644
--- a/data_diff/thread_utils.py
+++ b/data_diff/thread_utils.py
@@ -5,7 +5,7 @@
 from concurrent.futures import ThreadPoolExecutor
 from concurrent.futures.thread import _WorkItem
 from time import sleep
-from typing import Callable, Iterator, Optional
+from typing import Any, Callable, Iterator, Optional
 
 import attrs
 
@@ -80,7 +80,7 @@ def _worker(self, fn, *args, **kwargs):
     def submit(self, fn: Callable, *args, priority: int = 0, **kwargs):
         self._futures.append(self._pool.submit(self._worker, fn, *args, priority=priority, **kwargs))
 
-    def __iter__(self) -> Iterator:
+    def __iter__(self) -> Iterator[Any]:
         while True:
             if self._exception:
                 raise self._exception
diff --git a/tests/test_database_types.py b/tests/test_database_types.py
index 2ba7a1e8b..4bbeb0eae 100644
--- a/tests/test_database_types.py
+++ b/tests/test_database_types.py
@@ -8,9 +8,11 @@
 import logging
 from decimal import Decimal
 from itertools import islice, repeat, chain
+from typing import Iterator
 
 from parameterized import parameterized
 
+from data_diff.databases.base import Row
 from data_diff.utils import number_to_human
 from data_diff.queries.api import table, commit, this, Code
 from data_diff.queries.api import insert_rows_in_batches
@@ -371,7 +373,7 @@ def __init__(self, table_path, conn) -> None:
         self.table_path = table_path
         self.conn = conn
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[Row]:
         last_id = 0
         while True:
             query = (
@@ -402,7 +404,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[datetime]:
         initial = datetime(2000, 1, 1, 0, 0, 0, 0)
         step = timedelta(seconds=3, microseconds=571)
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
@@ -418,7 +420,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[int]:
         initial = -128
         step = 1
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
@@ -434,7 +436,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[bool]:
         return iter(self.MANUAL_FAKES[: self.max])
 
     def __len__(self) -> int:
@@ -465,7 +467,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[float]:
         initial = -10.0001
         step = 0.00571
         return islice(chain(self.MANUAL_FAKES, accumulate(repeat(step), initial=initial)), self.max)
@@ -482,7 +484,7 @@ def __init__(self, max) -> None:
     def __len__(self) -> int:
         return self.max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[uuid.UUID]:
         return (uuid.uuid1(i) for i in range(self.max))
 
 
@@ -495,7 +497,7 @@ def __init__(self, max) -> None:
         super().__init__()
         self.max = max
 
-    def __iter__(self):
+    def __iter__(self) -> Iterator[str]:
         return iter(self.MANUAL_FAKES[: self.max])
 
     def __len__(self) -> int:

From 001f63f0e2557da82b8a1c1dec9506f9dcab94b7 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:52:07 +0100
Subject: [PATCH 73/99] Annotate lazy ops and DSL magic methods

---
 data_diff/parse_time.py          |  2 +-
 data_diff/queries/api.py         | 30 +++++++++---------
 data_diff/queries/ast_classes.py | 54 ++++++++++++++++----------------
 3 files changed, 43 insertions(+), 43 deletions(-)

diff --git a/data_diff/parse_time.py b/data_diff/parse_time.py
index 39924798e..b7306df76 100644
--- a/data_diff/parse_time.py
+++ b/data_diff/parse_time.py
@@ -33,7 +33,7 @@ class ParseError(ValueError):
 UNITS_STR = ", ".join(sorted(TIME_UNITS.keys()))
 
 
-def string_similarity(a, b):
+def string_similarity(a, b) -> SequenceMatcher:
     return SequenceMatcher(None, a, b).ratio()
 
 
diff --git a/data_diff/queries/api.py b/data_diff/queries/api.py
index 82786871a..02ee3c6d1 100644
--- a/data_diff/queries/api.py
+++ b/data_diff/queries/api.py
@@ -26,7 +26,7 @@ def join(*tables: ITable) -> Join:
     return Join(tables)
 
 
-def leftjoin(*tables: ITable):
+def leftjoin(*tables: ITable) -> Join:
     """Left-joins a sequence of table expressions.
 
     See Also: ``join()``
@@ -34,7 +34,7 @@ def leftjoin(*tables: ITable):
     return Join(tables, "LEFT")
 
 
-def rightjoin(*tables: ITable):
+def rightjoin(*tables: ITable) -> Join:
     """Right-joins a sequence of table expressions.
 
     See Also: ``join()``
@@ -42,7 +42,7 @@ def rightjoin(*tables: ITable):
     return Join(tables, "RIGHT")
 
 
-def outerjoin(*tables: ITable):
+def outerjoin(*tables: ITable) -> Join:
     """Outer-joins a sequence of table expressions.
 
     See Also: ``join()``
@@ -50,7 +50,7 @@ def outerjoin(*tables: ITable):
     return Join(tables, "FULL OUTER")
 
 
-def cte(expr: Expr, *, name: Optional[str] = None, params: Sequence[str] = None):
+def cte(expr: Expr, *, name: Optional[str] = None, params: Sequence[str] = None) -> Cte:
     """Define a CTE"""
     return Cte(expr, name, params)
 
@@ -72,7 +72,7 @@ def table(*path: str, schema: Union[dict, CaseAwareMapping] = None) -> TablePath
     return TablePath(path, schema)
 
 
-def or_(*exprs: Expr):
+def or_(*exprs: Expr) -> Union[BinBoolOp, Expr]:
     """Apply OR between a sequence of boolean expressions"""
     exprs = args_as_tuple(exprs)
     if len(exprs) == 1:
@@ -80,7 +80,7 @@ def or_(*exprs: Expr):
     return BinBoolOp("OR", exprs)
 
 
-def and_(*exprs: Expr):
+def and_(*exprs: Expr) -> Union[BinBoolOp, Expr]:
     """Apply AND between a sequence of boolean expressions"""
     exprs = args_as_tuple(exprs)
     if len(exprs) == 1:
@@ -88,32 +88,32 @@ def and_(*exprs: Expr):
     return BinBoolOp("AND", exprs)
 
 
-def sum_(expr: Expr):
+def sum_(expr: Expr) -> Func:
     """Call SUM(expr)"""
     return Func("sum", [expr])
 
 
-def avg(expr: Expr):
+def avg(expr: Expr) -> Func:
     """Call AVG(expr)"""
     return Func("avg", [expr])
 
 
-def min_(expr: Expr):
+def min_(expr: Expr) -> Func:
     """Call MIN(expr)"""
     return Func("min", [expr])
 
 
-def max_(expr: Expr):
+def max_(expr: Expr) -> Func:
     """Call MAX(expr)"""
     return Func("max", [expr])
 
 
-def exists(expr: Expr):
+def exists(expr: Expr) -> Func:
     """Call EXISTS(expr)"""
     return Func("exists", [expr])
 
 
-def if_(cond: Expr, then: Expr, else_: Optional[Expr] = None):
+def if_(cond: Expr, then: Expr, else_: Optional[Expr] = None) -> CaseWhen:
     """Conditional expression, shortcut to when-then-else.
 
     Example:
@@ -125,7 +125,7 @@ def if_(cond: Expr, then: Expr, else_: Optional[Expr] = None):
     return when(cond).then(then).else_(else_)
 
 
-def when(*when_exprs: Expr):
+def when(*when_exprs: Expr) -> QB_When:
     """Start a when-then expression
 
     Example:
@@ -145,7 +145,7 @@ def when(*when_exprs: Expr):
     return CaseWhen([]).when(*when_exprs)
 
 
-def coalesce(*exprs):
+def coalesce(*exprs) -> Func:
     "Returns a call to COALESCE"
     exprs = args_as_tuple(exprs)
     return Func("COALESCE", exprs)
@@ -160,7 +160,7 @@ def insert_rows_in_batches(db, tbl: TablePath, rows, *, columns=None, batch_size
         db.query(tbl.insert_rows(batch, columns=columns))
 
 
-def current_timestamp():
+def current_timestamp() -> CurrentTimestamp:
     """Returns CURRENT_TIMESTAMP() or NOW()"""
     return CurrentTimestamp()
 
diff --git a/data_diff/queries/ast_classes.py b/data_diff/queries/ast_classes.py
index 348a58ca8..0580e8247 100644
--- a/data_diff/queries/ast_classes.py
+++ b/data_diff/queries/ast_classes.py
@@ -45,7 +45,7 @@ def _dfs_values(self):
                 if isinstance(v, ExprNode):
                     yield from v._dfs_values()
 
-    def cast_to(self, to):
+    def cast_to(self, to) -> "Cast":
         return Cast(self, to)
 
 
@@ -110,7 +110,7 @@ def select(self, *exprs, distinct=SKIP, optimizer_hints=SKIP, **named_exprs) ->
         resolve_names(self.source_table, exprs)
         return Select.make(self, columns=exprs, distinct=distinct, optimizer_hints=optimizer_hints)
 
-    def where(self, *exprs):
+    def where(self, *exprs) -> "Select":
         """Filter the rows, based on the given predicates. (aka Selection)"""
         exprs = args_as_tuple(exprs)
         exprs = _drop_skips(exprs)
@@ -120,7 +120,7 @@ def where(self, *exprs):
         resolve_names(self.source_table, exprs)
         return Select.make(self, where_exprs=exprs)
 
-    def order_by(self, *exprs):
+    def order_by(self, *exprs) -> "Select":
         """Order the rows lexicographically, according to the given expressions."""
         exprs = _drop_skips(exprs)
         if not exprs:
@@ -129,14 +129,14 @@ def order_by(self, *exprs):
         resolve_names(self.source_table, exprs)
         return Select.make(self, order_by_exprs=exprs)
 
-    def limit(self, limit: int):
+    def limit(self, limit: int) -> "Select":
         """Stop yielding rows after the given limit. i.e. take the first 'n=limit' rows"""
         if limit is SKIP:
             return self
 
         return Select.make(self, limit_expr=limit)
 
-    def join(self, target: "ITable"):
+    def join(self, target: "ITable") -> "Join":
         """Join the current table with the target table, returning a new table containing both side-by-side.
 
         When joining, it's recommended to use explicit tables names, instead of `this`, in order to avoid potential name collisions.
@@ -180,7 +180,7 @@ def group_by(self, *keys) -> "GroupBy":
 
         return GroupBy(self, keys)
 
-    def _get_column(self, name: str):
+    def _get_column(self, name: str) -> "Column":
         if self.schema:
             name = self.schema.get_key(name)  # Get the actual name. Might be case-insensitive.
         return Column(self, name)
@@ -188,29 +188,29 @@ def _get_column(self, name: str):
     # def __getattr__(self, column):
     #     return self._get_column(column)
 
-    def __getitem__(self, column):
+    def __getitem__(self, column) -> "Column":
         if not isinstance(column, str):
             raise TypeError()
         return self._get_column(column)
 
-    def count(self):
+    def count(self) -> "Select":
         """SELECT count() FROM self"""
         return Select(self, [Count()])
 
-    def union(self, other: "ITable"):
+    def union(self, other: "ITable") -> "TableOp":
         """SELECT * FROM self UNION other"""
         return TableOp("UNION", self, other)
 
-    def union_all(self, other: "ITable"):
+    def union_all(self, other: "ITable") -> "TableOp":
         """SELECT * FROM self UNION ALL other"""
         return TableOp("UNION ALL", self, other)
 
-    def minus(self, other: "ITable"):
+    def minus(self, other: "ITable") -> "TableOp":
         """SELECT * FROM self EXCEPT other"""
         # aka
         return TableOp("EXCEPT", self, other)
 
-    def intersect(self, other: "ITable"):
+    def intersect(self, other: "ITable") -> "TableOp":
         """SELECT * FROM self INTERSECT other"""
         return TableOp("INTERSECT", self, other)
 
@@ -233,51 +233,51 @@ def type(self) -> Optional[type]:
 
 @attrs.define(frozen=False, eq=False)
 class LazyOps:
-    def __add__(self, other):
+    def __add__(self, other) -> "BinOp":
         return BinOp("+", [self, other])
 
-    def __sub__(self, other):
+    def __sub__(self, other) -> "BinOp":
         return BinOp("-", [self, other])
 
-    def __neg__(self):
+    def __neg__(self) -> "UnaryOp":
         return UnaryOp("-", self)
 
-    def __gt__(self, other):
+    def __gt__(self, other) -> "BinBoolOp":
         return BinBoolOp(">", [self, other])
 
-    def __ge__(self, other):
+    def __ge__(self, other) -> "BinBoolOp":
         return BinBoolOp(">=", [self, other])
 
-    def __eq__(self, other):
+    def __eq__(self, other) -> "BinBoolOp":
         if other is None:
             return BinBoolOp("IS", [self, None])
         return BinBoolOp("=", [self, other])
 
-    def __lt__(self, other):
+    def __lt__(self, other) -> "BinBoolOp":
         return BinBoolOp("<", [self, other])
 
-    def __le__(self, other):
+    def __le__(self, other) -> "BinBoolOp":
         return BinBoolOp("<=", [self, other])
 
-    def __or__(self, other):
+    def __or__(self, other) -> "BinBoolOp":
         return BinBoolOp("OR", [self, other])
 
-    def __and__(self, other):
+    def __and__(self, other) -> "BinBoolOp":
         return BinBoolOp("AND", [self, other])
 
-    def is_distinct_from(self, other):
+    def is_distinct_from(self, other) -> "IsDistinctFrom":
         return IsDistinctFrom(self, other)
 
-    def like(self, other):
+    def like(self, other) -> "BinBoolOp":
         return BinBoolOp("LIKE", [self, other])
 
-    def sum(self):
+    def sum(self) -> "Func":
         return Func("SUM", [self])
 
-    def max(self):
+    def max(self) -> "Func":
         return Func("MAX", [self])
 
-    def min(self):
+    def min(self) -> "Func":
         return Func("MIN", [self])
 
 

From 1c62044516aa93cdef1db6d19ec099acf9d3c259 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:59:24 +0100
Subject: [PATCH 74/99] Annotate methods with clearly no results

---
 data_diff/__main__.py          | 10 ++++------
 data_diff/cloud/data_source.py |  2 +-
 data_diff/config.py            |  2 +-
 data_diff/databases/base.py    |  2 +-
 data_diff/dbt_parser.py        |  2 +-
 data_diff/info_tree.py         |  8 +++++---
 data_diff/queries/api.py       |  2 +-
 data_diff/query_utils.py       |  4 ++--
 data_diff/thread_utils.py      |  6 +++---
 data_diff/tracking.py          | 12 ++++++------
 data_diff/utils.py             |  4 ++--
 11 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/data_diff/__main__.py b/data_diff/__main__.py
index 0fe510bce..02f3b31d1 100644
--- a/data_diff/__main__.py
+++ b/data_diff/__main__.py
@@ -77,7 +77,7 @@ def _get_schema(pair: Tuple[Database, DbPath]) -> Dict[str, RawColumnInfo]:
     return db.query_table_schema(table_path)
 
 
-def diff_schemas(table1, table2, schema1, schema2, columns):
+def diff_schemas(table1, table2, schema1, schema2, columns) -> None:
     logging.info("Diffing schemas...")
     attrs = "name", "type", "datetime_precision", "numeric_precision", "numeric_scale"
     for c in columns:
@@ -281,7 +281,7 @@ def write_usage(self, prog: str, args: str = "", prefix: Optional[str] = None) -
     default=None,
     help="Override the dbt production schema configuration within dbt_project.yml",
 )
-def main(conf, run, **kw):
+def main(conf, run, **kw) -> None:
     log_handlers = _get_log_handlers(kw["dbt"])
     if kw["table2"] is None and kw["database2"]:
         # Use the "database table table" form
@@ -341,9 +341,7 @@ def main(conf, run, **kw):
                 production_schema_flag=kw["prod_schema"],
             )
         else:
-            return _data_diff(
-                dbt_project_dir=project_dir_override, dbt_profiles_dir=profiles_dir_override, state=state, **kw
-            )
+            _data_diff(dbt_project_dir=project_dir_override, dbt_profiles_dir=profiles_dir_override, state=state, **kw)
     except Exception as e:
         logging.error(e)
         raise
@@ -389,7 +387,7 @@ def _data_diff(
     threads1=None,
     threads2=None,
     __conf__=None,
-):
+) -> None:
     if limit and stats:
         logging.error("Cannot specify a limit when using the -s/--stats switch")
         return
diff --git a/data_diff/cloud/data_source.py b/data_diff/cloud/data_source.py
index 32fd89b92..3f3b2e16f 100644
--- a/data_diff/cloud/data_source.py
+++ b/data_diff/cloud/data_source.py
@@ -46,7 +46,7 @@ def process_response(self, value: str) -> str:
         return value
 
 
-def _validate_temp_schema(temp_schema: str):
+def _validate_temp_schema(temp_schema: str) -> None:
     if len(temp_schema.split(".")) != 2:
         raise ValueError("Temporary schema should have a format <database>.<schema>")
 
diff --git a/data_diff/config.py b/data_diff/config.py
index 1b091f074..3c4cbef99 100644
--- a/data_diff/config.py
+++ b/data_diff/config.py
@@ -99,7 +99,7 @@ def _apply_config(config: Dict[str, Any], run_name: str, kw: Dict[str, Any]):
 _ENV_VAR_PATTERN = r"\$\{([A-Za-z0-9_]+)\}"
 
 
-def _resolve_env(config: Dict[str, Any]):
+def _resolve_env(config: Dict[str, Any]) -> None:
     """
     Resolve environment variables referenced as ${ENV_VAR_NAME}.
     Missing environment variables are replaced with an empty string.
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 7d1640868..1f57d7712 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -188,7 +188,7 @@ class ThreadLocalInterpreter:
     compiler: Compiler
     gen: Generator
 
-    def apply_queries(self, callback: Callable[[str], Any]):
+    def apply_queries(self, callback: Callable[[str], Any]) -> None:
         q: Expr = next(self.gen)
         while True:
             sql = self.compiler.database.dialect.compile(self.compiler, q)
diff --git a/data_diff/dbt_parser.py b/data_diff/dbt_parser.py
index 0d864a573..eda5f6c57 100644
--- a/data_diff/dbt_parser.py
+++ b/data_diff/dbt_parser.py
@@ -50,7 +50,7 @@ def try_get_dbt_runner():
 
 # ProfileRenderer.render_data() fails without instantiating global flag MACRO_DEBUGGING in dbt-core 1.5
 # hacky but seems to be a bug on dbt's end
-def try_set_dbt_flags():
+def try_set_dbt_flags() -> None:
     try:
         from dbt.flags import set_flags
 
diff --git a/data_diff/info_tree.py b/data_diff/info_tree.py
index bc9430de1..a9683c20b 100644
--- a/data_diff/info_tree.py
+++ b/data_diff/info_tree.py
@@ -18,13 +18,15 @@ class SegmentInfo:
     rowcounts: Dict[int, int] = attrs.field(factory=dict)
     max_rows: Optional[int] = None
 
-    def set_diff(self, diff: List[Union[Tuple[Any, ...], List[Any]]], schema: Optional[Tuple[Tuple[str, type]]] = None):
+    def set_diff(
+        self, diff: List[Union[Tuple[Any, ...], List[Any]]], schema: Optional[Tuple[Tuple[str, type]]] = None
+    ) -> None:
         self.diff_schema = schema
         self.diff = diff
         self.diff_count = len(diff)
         self.is_diff = self.diff_count > 0
 
-    def update_from_children(self, child_infos):
+    def update_from_children(self, child_infos) -> None:
         child_infos = list(child_infos)
         assert child_infos
 
@@ -53,7 +55,7 @@ def add_node(self, table1: TableSegment, table2: TableSegment, max_rows: Optiona
         self.children.append(node)
         return node
 
-    def aggregate_info(self):
+    def aggregate_info(self) -> None:
         if self.children:
             for c in self.children:
                 c.aggregate_info()
diff --git a/data_diff/queries/api.py b/data_diff/queries/api.py
index 02ee3c6d1..0ff787190 100644
--- a/data_diff/queries/api.py
+++ b/data_diff/queries/api.py
@@ -151,7 +151,7 @@ def coalesce(*exprs) -> Func:
     return Func("COALESCE", exprs)
 
 
-def insert_rows_in_batches(db, tbl: TablePath, rows, *, columns=None, batch_size=1024 * 8):
+def insert_rows_in_batches(db, tbl: TablePath, rows, *, columns=None, batch_size=1024 * 8) -> None:
     assert batch_size > 0
     rows = list(rows)
 
diff --git a/data_diff/query_utils.py b/data_diff/query_utils.py
index a48877288..ed753d31d 100644
--- a/data_diff/query_utils.py
+++ b/data_diff/query_utils.py
@@ -23,7 +23,7 @@ def _drop_table(name: DbPath):
     yield commit
 
 
-def drop_table(db, tbl):
+def drop_table(db, tbl) -> None:
     if isinstance(db, Oracle):
         db.query(_drop_table_oracle(tbl))
     else:
@@ -51,6 +51,6 @@ def _append_to_table(path: DbPath, expr: Expr):
     yield commit
 
 
-def append_to_table(db, path, expr):
+def append_to_table(db, path, expr) -> None:
     f = _append_to_table_oracle if isinstance(db, Oracle) else _append_to_table
     db.query(f(path, expr))
diff --git a/data_diff/thread_utils.py b/data_diff/thread_utils.py
index 1b451a48d..2b9bb3db3 100644
--- a/data_diff/thread_utils.py
+++ b/data_diff/thread_utils.py
@@ -19,7 +19,7 @@ class AutoPriorityQueue(PriorityQueue):
 
     _counter = itertools.count().__next__
 
-    def put(self, item: Optional[_WorkItem], block=True, timeout=None):
+    def put(self, item: Optional[_WorkItem], block=True, timeout=None) -> None:
         priority = item.kwargs.pop("priority") if item is not None else 0
         super().put((-priority, self._counter(), item), block, timeout)
 
@@ -66,7 +66,7 @@ def __init__(self, max_workers: Optional[int] = None, yield_list: bool = False)
         self._exception = None
         self.yield_list = yield_list
 
-    def _worker(self, fn, *args, **kwargs):
+    def _worker(self, fn, *args, **kwargs) -> None:
         try:
             res = fn(*args, **kwargs)
             if res is not None:
@@ -77,7 +77,7 @@ def _worker(self, fn, *args, **kwargs):
         except Exception as e:
             self._exception = e
 
-    def submit(self, fn: Callable, *args, priority: int = 0, **kwargs):
+    def submit(self, fn: Callable, *args, priority: int = 0, **kwargs) -> None:
         self._futures.append(self._pool.submit(self._worker, fn, *args, priority=priority, **kwargs))
 
     def __iter__(self) -> Iterator[Any]:
diff --git a/data_diff/tracking.py b/data_diff/tracking.py
index 42f44dbb9..4c7297c29 100644
--- a/data_diff/tracking.py
+++ b/data_diff/tracking.py
@@ -80,7 +80,7 @@ def bool_notify_about_extension() -> bool:
 entrypoint_name = "Python API"
 
 
-def disable_tracking():
+def disable_tracking() -> None:
     global g_tracking_enabled
     g_tracking_enabled = False
 
@@ -89,7 +89,7 @@ def is_tracking_enabled():
     return g_tracking_enabled
 
 
-def set_entrypoint_name(s):
+def set_entrypoint_name(s) -> None:
     global entrypoint_name
     entrypoint_name = s
 
@@ -99,17 +99,17 @@ def set_entrypoint_name(s):
 dbt_project_id = None
 
 
-def set_dbt_user_id(s):
+def set_dbt_user_id(s) -> None:
     global dbt_user_id
     dbt_user_id = s
 
 
-def set_dbt_version(s):
+def set_dbt_version(s) -> None:
     global dbt_version
     dbt_version = s
 
 
-def set_dbt_project_id(s):
+def set_dbt_project_id(s) -> None:
     global dbt_project_id
     dbt_project_id = s
 
@@ -201,7 +201,7 @@ def create_email_signup_event_json(email: str) -> Dict[str, Any]:
     }
 
 
-def send_event_json(event_json):
+def send_event_json(event_json) -> None:
     if not g_tracking_enabled:
         raise RuntimeError("Won't send; tracking is disabled!")
 
diff --git a/data_diff/utils.py b/data_diff/utils.py
index 4e2942dff..c4175426c 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -93,13 +93,13 @@ def __iter__(self) -> Iterator[V]:
     def __len__(self) -> int:
         return len(self._dict)
 
-    def __setitem__(self, key: str, value):
+    def __setitem__(self, key: str, value) -> None:
         k = key.lower()
         if k in self._dict:
             key = self._dict[k][0]
         self._dict[k] = key, value
 
-    def __delitem__(self, key: str):
+    def __delitem__(self, key: str) -> None:
         del self._dict[key.lower()]
 
     def get_key(self, key: str) -> str:

From ff76f946f58675f5d4511d835497f2e1b9d1b45d Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Sun, 31 Dec 2023 18:59:48 +0100
Subject: [PATCH 75/99] Annotate regular methods with clear result types

---
 data_diff/databases/base.py       | 2 +-
 data_diff/databases/bigquery.py   | 4 ++--
 data_diff/databases/databricks.py | 2 +-
 data_diff/databases/mssql.py      | 4 ++--
 data_diff/databases/mysql.py      | 4 ++--
 data_diff/databases/oracle.py     | 4 ++--
 data_diff/databases/vertica.py    | 2 +-
 data_diff/parse_time.py           | 4 ++--
 data_diff/table_segment.py        | 2 +-
 data_diff/tracking.py             | 4 ++--
 10 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 1f57d7712..d6549f714 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -131,7 +131,7 @@ def dialect(self) -> "BaseDialect":
     def compile(self, elem, params=None) -> str:
         return self.dialect.compile(self, elem, params)
 
-    def new_unique_name(self, prefix="tmp"):
+    def new_unique_name(self, prefix="tmp") -> str:
         self._counter[0] += 1
         return f"{prefix}{self._counter[0]}"
 
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index 2216bf412..c4470ee69 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -85,10 +85,10 @@ class Dialect(BaseDialect):
     def random(self) -> str:
         return "RAND()"
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f"`{s}`"
 
-    def to_string(self, s: str):
+    def to_string(self, s: str) -> str:
         return f"cast({s} as string)"
 
     def type_repr(self, t) -> str:
diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index dd83a95c5..c3e40123d 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -65,7 +65,7 @@ def type_repr(self, t) -> str:
         except KeyError:
             return super().type_repr(t)
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f"`{s}`"
 
     def to_string(self, s: str) -> str:
diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index c9ec09bfe..e4f841ef7 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -76,7 +76,7 @@ class Dialect(BaseDialect):
         "json": JSON,
     }
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f"[{s}]"
 
     def set_timezone_to_utc(self) -> str:
@@ -93,7 +93,7 @@ def current_schema(self) -> str:
         FROM sys.database_principals
         WHERE name = CURRENT_USER"""
 
-    def to_string(self, s: str):
+    def to_string(self, s: str) -> str:
         # Both convert(varchar(max), …) and convert(text, …) do work.
         return f"CONVERT(VARCHAR(MAX), {s})"
 
diff --git a/data_diff/databases/mysql.py b/data_diff/databases/mysql.py
index 941673b04..1ee04460b 100644
--- a/data_diff/databases/mysql.py
+++ b/data_diff/databases/mysql.py
@@ -70,10 +70,10 @@ class Dialect(BaseDialect):
         "boolean": Boolean,
     }
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f"`{s}`"
 
-    def to_string(self, s: str):
+    def to_string(self, s: str) -> str:
         return f"cast({s} as char)"
 
     def is_distinct_from(self, a: str, b: str) -> str:
diff --git a/data_diff/databases/oracle.py b/data_diff/databases/oracle.py
index 36d154a06..f5960476d 100644
--- a/data_diff/databases/oracle.py
+++ b/data_diff/databases/oracle.py
@@ -59,10 +59,10 @@ class Dialect(
     ROUNDS_ON_PREC_LOSS = True
     PLACEHOLDER_TABLE = "DUAL"
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f'"{s}"'
 
-    def to_string(self, s: str):
+    def to_string(self, s: str) -> str:
         return f"cast({s} as varchar(1024))"
 
     def limit_select(
diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index f997601d4..cfe046d28 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -60,7 +60,7 @@ class Dialect(BaseDialect):
     # https://www.vertica.com/docs/9.3.x/HTML/Content/Authoring/SQLReferenceManual/DataTypes/Numeric/NUMERIC.htm#Default
     DEFAULT_NUMERIC_PRECISION = 15
 
-    def quote(self, s: str):
+    def quote(self, s: str) -> str:
         return f'"{s}"'
 
     def concat(self, items: List[str]) -> str:
diff --git a/data_diff/parse_time.py b/data_diff/parse_time.py
index b7306df76..ec80ccb44 100644
--- a/data_diff/parse_time.py
+++ b/data_diff/parse_time.py
@@ -53,7 +53,7 @@ def parse_time_atom(count, unit):
     return count, unit
 
 
-def parse_time_delta(t: str):
+def parse_time_delta(t: str) -> timedelta:
     time_dict = {}
     while t:
         m = TIME_RE.match(t)
@@ -70,5 +70,5 @@ def parse_time_delta(t: str):
     return timedelta(**time_dict)
 
 
-def parse_time_before(time: datetime, delta: str):
+def parse_time_before(time: datetime, delta: str) -> datetime:
     return time - parse_time_delta(delta)
diff --git a/data_diff/table_segment.py b/data_diff/table_segment.py
index 4e9f41b10..4e712445d 100644
--- a/data_diff/table_segment.py
+++ b/data_diff/table_segment.py
@@ -138,7 +138,7 @@ def __attrs_post_init__(self) -> None:
                 f"Error: min_update expected to be smaller than max_update! ({self.min_update} >= {self.max_update})"
             )
 
-    def _where(self):
+    def _where(self) -> Optional[str]:
         return f"({self.where})" if self.where else None
 
     def _with_raw_schema(self, raw_schema: Dict[str, RawColumnInfo]) -> Self:
diff --git a/data_diff/tracking.py b/data_diff/tracking.py
index 4c7297c29..0fad464ac 100644
--- a/data_diff/tracking.py
+++ b/data_diff/tracking.py
@@ -85,7 +85,7 @@ def disable_tracking() -> None:
     g_tracking_enabled = False
 
 
-def is_tracking_enabled():
+def is_tracking_enabled() -> bool:
     return g_tracking_enabled
 
 
@@ -114,7 +114,7 @@ def set_dbt_project_id(s) -> None:
     dbt_project_id = s
 
 
-def get_anonymous_id():
+def get_anonymous_id() -> str:
     global g_anonymous_id
     if g_anonymous_id is None:
         profile = _load_profile()

From 42e6a9f42d49c4d71d7e51942a1938d58ad54ee3 Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Tue, 9 Jan 2024 08:36:46 +1300
Subject: [PATCH 76/99] Update readme for clarity(#843)

Co-authored-by: Sung Won Chung <sung@datafold.com>
---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 3c6e77f22..d830d3bb6 100644
--- a/README.md
+++ b/README.md
@@ -209,7 +209,8 @@ For detailed algorithm and performance insights, explore [here](https://github.c
 
 
 # data-diff OSS & Datafold Cloud
-data-diff is an open source utility for running stateless diffs on your local computer for a great single player experience.
+
+data-diff is an open source utility for running stateless diffs as a great single player experience.
 
 Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a company-wide experience to both supercharge your data diffing CLI experience (ex: data-diff --dbt --cloud) and run diffs manually in the UI. This includes [column-level lineage](https://www.datafold.com/column-level-lineage), [CI testing](https://docs.datafold.com/deployment_testing/how_it_works/), and diff history.
 

From e619e4223c7a1e494a2fc973d5669429db19c9ce Mon Sep 17 00:00:00 2001
From: Sarad Mohanan <sarad.mohanan@gmail.com>
Date: Tue, 9 Jan 2024 22:44:58 +0530
Subject: [PATCH 77/99] Ability to install all oss supported database adapters.
 (#842)

* Ability to install all database adapters.

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* Update pyproject.toml

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Update README.md

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Update pyproject.toml

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* pyodbc comment and breaking dependency

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* update readme

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* Update pyproject.toml

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Update README.md

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* remove cloud dbs

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* Update README.md

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

---------

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>
Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>
---
 README.md      | 23 ++++++++++++++---------
 pyproject.toml |  6 +++++-
 2 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/README.md b/README.md
index d830d3bb6..80852d372 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ data-diff is a powerful tool for comparing data when you're moving it between sy
 - **Converting SQL** to a new transformation framework (e.g., stored procedures -> dbt)
 - Continuously **replicating data** from an OLTP database to OLAP data warehouse (e.g., MySQL -> Redshift)
 
-### Data Development Testing 
+### Data Development Testing
 When developing SQL code, data-diff helps you validate and preview changes by comparing data between development/staging environments and production. Here's how it works:
 1. Make a change to your SQL code
 2. Run the SQL code to create a new dataset
@@ -33,7 +33,7 @@ When developing SQL code, data-diff helps you validate and preview changes by co
 # dbt Integration
   <p align="left">
   <img alt="dbt" src="https://seeklogo.com/images/D/dbt-logo-E4B0ED72A2-seeklogo.com.png" width="10%" />
-  </p> 
+  </p>
 
 data-diff integrates with [dbt Core](https://github.com/dbt-labs/dbt-core) to seamlessly compare local development to production datasets.
 
@@ -46,9 +46,9 @@ Learn more about how data-diff works with dbt:
 # Getting Started
 
 ### ⚡ Validating dbt model changes between dev and prod
-Looking to use data-diff in dbt development? 
+Looking to use data-diff in dbt development?
 
-Development testing with Datafold enables you to see the impact of dbt code changes on data as you write the code, whether in your IDE or CLI. 
+Development testing with Datafold enables you to see the impact of dbt code changes on data as you write the code, whether in your IDE or CLI.
 
  Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/cli) to get started with a development testing workflow!
 
@@ -61,6 +61,11 @@ To compare data between databases, install `data-diff` with specific database ad
 pip install data-diff 'data-diff[postgresql,snowflake]' -U
 ```
 
+Additionally, you can install all open source supported database adapters as follows.
+```
+pip install data-diff 'data-diff[all-oss-supported-dbs]' -U
+```
+
 2. Run `data-diff` with connection URIs
 
 Then, we compare tables between PostgreSQL and Snowflake using the hashdiff algorithm:
@@ -75,13 +80,13 @@ data-diff \
   -c <columns to compare> \
   -w <filter condition>
 ```
-3. Set up your configuration 
+3. Set up your configuration
 
 You can use a `toml` configuration file to run your `data-diff` job. In this example, we compare tables between MotherDuck (hosted DuckDB) and Snowflake using the hashdiff algorithm:
 
 ```toml
 ## DATABASE CONNECTION ##
-[database.duckdb_connection] 
+[database.duckdb_connection]
   driver = "duckdb"
   # filepath = "datafold_demo.duckdb" # local duckdb file example
   # filepath = "md:" # default motherduck connection example
@@ -202,10 +207,10 @@ Your database not listed here?
 * Time complexity approximates COUNT(*) operation when there are few differences
 * Performance degrades when datasets have a large number of differences
 
-</details>  
+</details>
 <br>
 
-For detailed algorithm and performance insights, explore [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md), or head to our docs to [learn more about how Datafold diffs data](https://docs.datafold.com/data_diff/how-datafold-diffs-data). 
+For detailed algorithm and performance insights, explore [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md), or head to our docs to [learn more about how Datafold diffs data](https://docs.datafold.com/data_diff/how-datafold-diffs-data).
 
 
 # data-diff OSS & Datafold Cloud
@@ -216,7 +221,7 @@ Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a
 
 ## Contributors
 
-We thank everyone who contributed so far! 
+We thank everyone who contributed so far!
 
 We'd love to see your face here: [Contributing Instructions](CONTRIBUTING.md)
 
diff --git a/pyproject.toml b/pyproject.toml
index 0fe15b4c2..dfa2e4adf 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -74,12 +74,16 @@ redshift = ["psycopg2"]
 snowflake = ["snowflake-connector-python", "cryptography"]
 presto = ["presto-python-client"]
 oracle = ["oracledb"]
-mssql = ["pyodbc"]
+mssql = ["pyodbc"]  # natively supported in Datafold Cloud only
 # databricks = ["databricks-sql-connector"]
 trino = ["trino"]
 clickhouse = ["clickhouse-driver"]
 vertica = ["vertica-python"]
 duckdb = ["duckdb"]
+all-oss-supported-dbs = [
+    "preql", "mysql-connector-python", "psycopg2", "snowflake-connector-python", "cryptography", "presto-python-client",
+    "oracledb", "trino", "clickhouse-driver", "vertica-python", "duckdb"
+]
 
 [tool.poetry.group.dev.dependencies]
 pre-commit = "^3.5.0"

From 566dfef4455532307a0b214badbf7f8048c7c451 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 9 Jan 2024 16:17:11 -0700
Subject: [PATCH 78/99] fix for Warning: poetry.lock is not consistent with
 pyproject.toml

---
 poetry.lock | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/poetry.lock b/poetry.lock
index 073367c0c..ff2b5f97d 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1476,6 +1476,8 @@ files = [
     {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
     {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
     {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
     {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
@@ -2300,6 +2302,7 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link
 testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
 
 [extras]
+all-oss-supported-dbs = ["clickhouse-driver", "cryptography", "duckdb", "mysql-connector-python", "oracledb", "preql", "presto-python-client", "psycopg2", "snowflake-connector-python", "trino", "vertica-python"]
 clickhouse = ["clickhouse-driver"]
 duckdb = ["duckdb"]
 mssql = ["pyodbc"]
@@ -2316,4 +2319,4 @@ vertica = ["vertica-python"]
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8.0"
-content-hash = "54f5248145c8920e27de3e781bb01461b3f68bc6335d75d8793b19dffd5f4163"
+content-hash = "ffdcb49e5602f6064e068f3924c64ab15d377cc320ae2c55df2d8c73d10f9588"

From e84164908f30461e29ae9a17be1a4d104cb8453f Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Tue, 9 Jan 2024 16:34:08 -0700
Subject: [PATCH 79/99] fix send_event_json

convert sets to list, don't include _ignored_columns_lock: threading.Lock in events
---
 data_diff/diff_tables.py |  2 ++
 data_diff/tracking.py    | 17 +++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 74376f639..0086b878e 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -213,6 +213,8 @@ def diff_tables(self, table1: TableSegment, table2: TableSegment, info_tree: Inf
     def _diff_tables_wrapper(self, table1: TableSegment, table2: TableSegment, info_tree: InfoTree) -> DiffResult:
         if is_tracking_enabled():
             options = attrs.asdict(self, recurse=False)
+            # not a useful event attribute
+            options.pop("_ignored_columns_lock")
             options["differ_name"] = type(self).__name__
             event_json = create_start_event_json(options)
             run_as_daemon(send_event_json, event_json)
diff --git a/data_diff/tracking.py b/data_diff/tracking.py
index 0fad464ac..2f2a33701 100644
--- a/data_diff/tracking.py
+++ b/data_diff/tracking.py
@@ -201,10 +201,27 @@ def create_email_signup_event_json(email: str) -> Dict[str, Any]:
     }
 
 
+def convert_sets_to_lists(obj):
+    """
+    Recursively convert sets in the given object to lists.
+    """
+    if isinstance(obj, set):
+        return list(obj)
+    elif isinstance(obj, dict):
+        return {k: convert_sets_to_lists(v) for k, v in obj.items()}
+    elif isinstance(obj, list):
+        return [convert_sets_to_lists(elem) for elem in obj]
+    else:
+        return obj
+
+
 def send_event_json(event_json) -> None:
     if not g_tracking_enabled:
         raise RuntimeError("Won't send; tracking is disabled!")
 
+    # Convert sets to lists in event_json
+    event_json = convert_sets_to_lists(event_json)
+
     headers = {
         "Content-Type": "application/json",
         "Authorization": "Basic MkhndE00SGNxOUJtZWlDcU5ZaHo3Tzl0a2pNOg==",

From e3054800f5687250e5b5a7d0faccf7f2eb557ceb Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 10 Jan 2024 12:59:08 +1300
Subject: [PATCH 80/99] Microsoft SQL Server Support Docs (#845)

* update supported dbs

* remove submods

* fix import

* remove submods again

* update lock

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
---
 README.md      |  3 ++-
 poetry.lock    | 33 ++++-----------------------------
 pyproject.toml |  6 +++---
 3 files changed, 9 insertions(+), 33 deletions(-)

diff --git a/README.md b/README.md
index 80852d372..3db79ea65 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,7 @@ pip install data-diff 'data-diff[postgresql,snowflake]' -U
 
 Additionally, you can install all open source supported database adapters as follows.
 ```
-pip install data-diff 'data-diff[all-oss-supported-dbs]' -U
+pip install data-diff 'data-diff[all-dbs]' -U
 ```
 
 2. Run `data-diff` with connection URIs
@@ -156,6 +156,7 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Redshift      |  🟢     | `redshift://<username>:<password>@<hostname>:5439/<database>`                                                                       |
 | DuckDB        |  🟢   | `duckdb://<filepath>`                                                                                          |
 | MotherDuck        |  🟢   | `duckdb://<filepath>`                                                                                                   |
+| Microsoft SQL Server        |  🟢   | `mssql://<user>:<password>@<host>/<database>/<schema>`                                                                                                   |
 | Oracle        |  🟡   | `oracle://<username>:<password>@<hostname>/servive_or_sid`                                                                          |
 | Presto        |  🟡   | `presto://<username>:<password>@<hostname>:8080/<database>`                                                                         |
 | Databricks    |  🟡   | `databricks://<http_path>:<access_token>@<server_hostname>/<catalog>/<schema>`                                                      |
diff --git a/poetry.lock b/poetry.lock
index 073367c0c..f4b6a6ccb 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -324,7 +324,6 @@ python-versions = ">=3.7, <4"
 files = [
     {file = "clickhouse-driver-0.2.6.tar.gz", hash = "sha256:028baf4d65a0b3f9e0ac5df248cab20657b51adbfce6c5427aa6c16a7318dda1"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e61d975081b74cae9efe7a64b1de1a8aec5643affb81b57487dcae7d195f250f"},
-    {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee0395b49bd8c0cd3dca6b3a4b9db347c1d300de83ee7b4f482a9d48b6c7af54"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d8aff4d3f0d78fd4b11e28ef344a5ee71d6850fef4a79e3265e0728b4d1d89"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b086bd658889af10205cb8307b714c8202bdfd05a4833fc7f4f82df2d88a963"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a1b6815d56a03398110c7f602a87ad767ecfd7a0869e61f2d8bfa0779dce2b"},
@@ -338,7 +337,6 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1960244de84d7888598180e69689d1ba7ec6c9c99cd2c080a76315a7a29a5cab"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:5a6bdfde4e2fb81414200303950ba75c3f7ee9249e4a997854ce18e1cb4beea9"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef0a9453a972ec32399cc93a510aec33fa4b9b1f0c5050a3a40e5d298a89a7aa"},
-    {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:95c13374741a8749980436603922ad7c476ae3b5e17850c50faba3879db66bdb"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d715d392eaadb43ded1c104354aebbc233f69bbf3919aa61beb7cc6ecdaa950a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d75d50265616a2779d0b2acaebf7253783e2b8ad0df3efa6d23f0db1c9bf50"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32f0e02c28e9a6f1c1f116d1aa14772e73beb7efd4f30490d9f171d39b40551a"},
@@ -351,20 +349,6 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3bdff826074af1b339fe9bff17844f6b8117080f895b8601f536b13a9d04f82a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win32.whl", hash = "sha256:c8c02606eabe4288045bbba497088b7fe976c34330c1066db9744fa09fef4a2a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:44df94940739a72a02716bb14ac8b683aef84b54b05783d96201ff334bcd88fb"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:079708ac620343736c2c8dace6663178156f4ded47bf25245b56147498d0d7de"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e13369cf516df6c33c156fe66cfff502f66fc25f2a515c761ed1480fc83b3aa9"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbc0bf957fc6d0163ee06ac02275bdb2f40d109fc225366e387358e78d968a43"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58b0ffb434fefe99b7419e09d6071a49773e9eb49c5ebeedf7c3180b40c2330"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0746dac9aa5cf2c275187aef16b67ae922ef257c82671948a6be86e19ee9cb2"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f1ce40c9a2715ea44be9a5c33cb5b08048c1ef5595a6739443473e4ba23fedf"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9499a2b2d5e856c7e8efd28da479df8a962e2497c70bf5e2d9a25875d520465"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8b2e849bb7102365a480d9d1083ed203a244f0c02a0fc973eab6078b3d14638d"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5846c50e2dfe0ce2f300275955a20f82422b1128b09ab5a9ea4d8a00d4ba8438"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:a12990b54b92b2a2598f144388e766d6261492408f2434738fe649423371894b"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:af14a5699fea890a1f8f022c624ca9f61994e15913cfaf4e0e58b1e4ac99540a"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:965fb8370eb7ee8a20cdf54d7c2fe024f587da692bd15e94dd2eee93a3c88f4b"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-win32.whl", hash = "sha256:9c552205d2b6125a99121080417c5c7bbc47af81ed15bb5ff9be464fed96bb68"},
-    {file = "clickhouse_driver-0.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:a58fb8b12a32d58ce0c72839293ec5bacc7904f3db36a82bb963f394dbb5f230"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f2a9abb8b1464985f7a480f956744736e611970ffc8ffd3eb0b46343a3a691e6"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e01696c450a2de41d586689dbaed0893d4de7469811abd3bf831a0483e723a"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0bb85760dabbef493aec985ad94612132ddeb5b81569cf0a7222f6cb7278eda"},
@@ -379,7 +363,6 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:48f47694d5e54af192a4aa2a24f947795c362ab40a253d088593880fede97568"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b783e5d3d12947c73d991bceb6b8765231512ab0ac6363823cdcd2c283c67a99"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d24e0acf8fef1d787851ae048e0168b2fb10297c3235cbb87974f78db37d3d3"},
-    {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27dc025f10a930aed453eec5ed9a0404e7b2db671da4a253109facf5c1ad1b4c"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d534c744b1b211241f8c58d2ad5fcfc465a0503011d9b9073c00e25507abcbf3"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:858b8039a1241591b63f368de9dbdef6c4e6466b6bf0e01d53d36f7091af7569"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21eb62e1de7d2d5483d121d1447e857030bf866d4f23572b0dedc515f9359cd0"},
@@ -393,7 +376,6 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win32.whl", hash = "sha256:b9b775f70371a7333ac828fe2bbd9473c94e18728ac6b70b2865cdee1f0d551f"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:d13fe44620750abcd4c93c067d6e44c8a1ea050856c4c27a5633ad8ff197a689"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e17995752eef4f742976abab03ff3f5b81edb9b9218b151abaf3534055fcf2b8"},
-    {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c23baf4b4185b3ee13332c05c201e242600e35deb8b0b0d95211e71d5eb3f59"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbd7e3e33d2bc5f32da2557e97299340a722f948790494a2e9efaed4635ff499"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c872e9fee17d278816fc30b4df4b10bedd8eec9efaa614c71725f147b00b30d"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c8af2761676cd306962a86cc87a4187efcfdaf253a0d908c8f8ef791277a7fe"},
@@ -1017,16 +999,6 @@ files = [
     {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
-    {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -1476,6 +1448,8 @@ files = [
     {file = "psycopg2-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:426f9f29bde126913a20a96ff8ce7d73fd8a216cfb323b1f04da402d452853c3"},
     {file = "psycopg2-2.9.9-cp311-cp311-win32.whl", hash = "sha256:ade01303ccf7ae12c356a5e10911c9e1c51136003a9a1d92f7aa9d010fb98372"},
     {file = "psycopg2-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:121081ea2e76729acfb0673ff33755e8703d45e926e416cb59bae3a86c6a4981"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win32.whl", hash = "sha256:d735786acc7dd25815e89cc4ad529a43af779db2e25aa7c626de864127e5a024"},
+    {file = "psycopg2-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:a7653d00b732afb6fc597e29c50ad28087dcb4fbfb28e86092277a559ae4e693"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:5e0d98cade4f0e0304d7d6f25bbfbc5bd186e07b38eac65379309c4ca3193efa"},
     {file = "psycopg2-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:7e2dacf8b009a1c1e843b5213a87f7c544b2b042476ed7755be813eaf4e8347a"},
     {file = "psycopg2-2.9.9-cp38-cp38-win32.whl", hash = "sha256:ff432630e510709564c01dafdbe996cb552e0b9f3f065eb89bdce5bd31fabf4c"},
@@ -2300,6 +2274,7 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link
 testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"]
 
 [extras]
+all-dbs = ["clickhouse-driver", "cryptography", "duckdb", "mysql-connector-python", "oracledb", "preql", "presto-python-client", "psycopg2", "pyodbc", "snowflake-connector-python", "trino", "vertica-python"]
 clickhouse = ["clickhouse-driver"]
 duckdb = ["duckdb"]
 mssql = ["pyodbc"]
@@ -2316,4 +2291,4 @@ vertica = ["vertica-python"]
 [metadata]
 lock-version = "2.0"
 python-versions = "^3.8.0"
-content-hash = "54f5248145c8920e27de3e781bb01461b3f68bc6335d75d8793b19dffd5f4163"
+content-hash = "3ba4fe6135b2011602f98b947cbee7c33cc7ac6ec8d80bf620ec5b381d4706f3"
diff --git a/pyproject.toml b/pyproject.toml
index dfa2e4adf..340cc1998 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -74,15 +74,15 @@ redshift = ["psycopg2"]
 snowflake = ["snowflake-connector-python", "cryptography"]
 presto = ["presto-python-client"]
 oracle = ["oracledb"]
-mssql = ["pyodbc"]  # natively supported in Datafold Cloud only
+mssql = ["pyodbc"]
 # databricks = ["databricks-sql-connector"]
 trino = ["trino"]
 clickhouse = ["clickhouse-driver"]
 vertica = ["vertica-python"]
 duckdb = ["duckdb"]
-all-oss-supported-dbs = [
+all-dbs = [
     "preql", "mysql-connector-python", "psycopg2", "snowflake-connector-python", "cryptography", "presto-python-client",
-    "oracledb", "trino", "clickhouse-driver", "vertica-python", "duckdb"
+    "oracledb", "pyodbc", "trino", "clickhouse-driver", "vertica-python", "duckdb"
 ]
 
 [tool.poetry.group.dev.dependencies]

From 6f0c4321c1eae03be0b4289443871345dc19be5e Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Wed, 10 Jan 2024 20:02:57 +1100
Subject: [PATCH 81/99] LAB-271 Redshift Spectrum type mapping

---
 data_diff/databases/redshift.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index d7bcd876b..a88e27ef2 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -10,6 +10,7 @@
     FractionalType,
     DbPath,
     TimestampTZ,
+    Integer
 )
 from data_diff.databases.postgresql import (
     BaseDialect,
@@ -31,6 +32,8 @@ class Dialect(PostgresqlDialect):
         "double": Float,
         "real": Float,
         "super": JSON,
+        "int": Integer,  # Redshift Spectrum
+        "float": Float,  # Redshift Spectrum
     }
     SUPPORTS_INDEXES = False
 

From d59eab7cbc39dac094394ce053a5dc618d26d1e5 Mon Sep 17 00:00:00 2001
From: teraamp <teraamp@users.noreply.github.com>
Date: Wed, 10 Jan 2024 09:08:40 +0000
Subject: [PATCH 82/99] style fixes by ruff

---
 data_diff/databases/redshift.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_diff/databases/redshift.py b/data_diff/databases/redshift.py
index a88e27ef2..356d31344 100644
--- a/data_diff/databases/redshift.py
+++ b/data_diff/databases/redshift.py
@@ -10,7 +10,7 @@
     FractionalType,
     DbPath,
     TimestampTZ,
-    Integer
+    Integer,
 )
 from data_diff.databases.postgresql import (
     BaseDialect,

From 8944e5fe81a0443e9fd6303308773698e07bac8a Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Thu, 11 Jan 2024 12:20:19 +0100
Subject: [PATCH 83/99] Detect duplicate rows on each side

---
 data_diff/hashdiff_tables.py | 36 ++++++++++++++++++++++++------------
 tests/test_diff_tables.py    |  6 +++---
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/data_diff/hashdiff_tables.py b/data_diff/hashdiff_tables.py
index 0984d9f1a..dd0c36647 100644
--- a/data_diff/hashdiff_tables.py
+++ b/data_diff/hashdiff_tables.py
@@ -39,22 +39,34 @@ def diff_sets(
     ignored_columns1: Collection[str],
     ignored_columns2: Collection[str],
 ) -> Iterator:
-    # Differ only by columns of interest (PKs+relevant-ignored). But yield with ignored ones!
-    sa: Set[_Row] = {tuple(val for col, val in safezip(columns1, row) if col not in ignored_columns1) for row in a}
-    sb: Set[_Row] = {tuple(val for col, val in safezip(columns2, row) if col not in ignored_columns2) for row in b}
-
-    # The first items are always the PK (see TableSegment.relevant_columns)
-    diffs_by_pks: Dict[_PK, List[Tuple[_Op, _Row]]] = defaultdict(list)
+    # Group full rows by PKs on each side. The first items are the PK: TableSegment.relevant_columns
+    rows_by_pks1: Dict[_PK, List[_Row]] = defaultdict(list)
+    rows_by_pks2: Dict[_PK, List[_Row]] = defaultdict(list)
     for row in a:
         pk: _PK = tuple(val for col, val in zip(key_columns1, row))
-        cutrow: _Row = tuple(val for col, val in zip(columns1, row) if col not in ignored_columns1)
-        if cutrow not in sb:
-            diffs_by_pks[pk].append(("-", row))
+        rows_by_pks1[pk].append(row)
     for row in b:
         pk: _PK = tuple(val for col, val in zip(key_columns2, row))
-        cutrow: _Row = tuple(val for col, val in zip(columns2, row) if col not in ignored_columns2)
-        if cutrow not in sa:
-            diffs_by_pks[pk].append(("+", row))
+        rows_by_pks2[pk].append(row)
+
+    # Mind that the same pk MUST go in full with all the -/+ rows all at once, for grouping.
+    diffs_by_pks: Dict[_PK, List[Tuple[_Op, _Row]]] = defaultdict(list)
+    for pk in sorted(set(rows_by_pks1) | set(rows_by_pks2)):
+        cutrows1: List[_Row] = [
+            tuple(val for col, val in zip(columns1, row1) if col not in ignored_columns1) for row1 in rows_by_pks1[pk]
+        ]
+        cutrows2: List[_Row] = [
+            tuple(val for col, val in zip(columns2, row2) if col not in ignored_columns2) for row2 in rows_by_pks2[pk]
+        ]
+
+        # Either side has 0 rows: a clearly exclusive row.
+        # Either side has 2+ rows: duplicates on either side, yield it all regardless of values.
+        # Both sides == 1: non-duplicate, non-exclusive, so check for values of interest.
+        if len(cutrows1) != 1 or len(cutrows2) != 1 or cutrows1 != cutrows2:
+            for row1 in rows_by_pks1[pk]:
+                diffs_by_pks[pk].append(("-", row1))
+            for row2 in rows_by_pks2[pk]:
+                diffs_by_pks[pk].append(("+", row2))
 
     warned_diff_cols = set()
     for diffs in (diffs_by_pks[pk] for pk in sorted(diffs_by_pks)):
diff --git a/tests/test_diff_tables.py b/tests/test_diff_tables.py
index 9a9750895..705bf55e8 100644
--- a/tests/test_diff_tables.py
+++ b/tests/test_diff_tables.py
@@ -818,11 +818,11 @@ def test_simple2(self):
         V1 = N + 1
         V2 = N * 1000 + 2
 
-        diffs = [(i, i + N) for i in range(N)]
+        diffs = [(i + 1, i + N) for i in range(N)]  # pk=[1..1000], no dupes
         self.connection.query(
             [
-                self.src_table.insert_rows(diffs + [(K, V1)]),
-                self.dst_table.insert_rows(diffs + [(0, V2)]),
+                self.src_table.insert_rows(diffs + [(K, V1)]),  # exclusive pk=1001
+                self.dst_table.insert_rows(diffs + [(0, V2)]),  # exclusive pk=0
                 commit,
             ]
         )

From a3410f0223311ded2d39d9291bb50cb77da42983 Mon Sep 17 00:00:00 2001
From: Valentin Khomutenko <valentine.khomutenko@gmail.com>
Date: Fri, 12 Jan 2024 14:08:32 +0100
Subject: [PATCH 84/99] improve error reporting for PK type mismatch

---
 data_diff/diff_tables.py | 9 +++++++--
 data_diff/errors.py      | 4 ++++
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 0086b878e..71fbf2c05 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -11,6 +11,7 @@
 
 import attrs
 
+from data_diff.errors import DataDiffMismatchingKeyTypesError
 from data_diff.info_tree import InfoTree, SegmentInfo
 from data_diff.utils import dbt_diff_string_template, run_as_daemon, safezip, getLogger, truncate_error, Vector
 from data_diff.thread_utils import ThreadedYielder
@@ -292,9 +293,13 @@ def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, in
             if not isinstance(kt, IKey):
                 raise NotImplementedError(f"Cannot use a column of type {kt} as a key")
 
-        for kt1, kt2 in safezip(key_types1, key_types2):
+        for i, (kt1, kt2) in enumerate(safezip(key_types1, key_types2)):
             if kt1.python_type is not kt2.python_type:
-                raise TypeError(f"Incompatible key types: {kt1} and {kt2}")
+                k1 = table1.key_columns[i]
+                k2 = table2.key_columns[i]
+                raise DataDiffMismatchingKeyTypesError(
+                    f"Key columns {k1} and {k2} can't be compared due to different types."
+                )
 
         # Query min/max values
         key_ranges = self._threaded_call_as_completed("query_key_range", [table1, table2])
diff --git a/data_diff/errors.py b/data_diff/errors.py
index 3b446b327..b4cb92b8a 100644
--- a/data_diff/errors.py
+++ b/data_diff/errors.py
@@ -68,3 +68,7 @@ class DataDiffCloudDiffTimedOut(Exception):
 
 class DataDiffSimpleSelectNotFound(Exception):
     "Raised when using --select on dbt < 1.5 and a model node is not found in the manifest."
+
+
+class DataDiffMismatchingKeyTypesError(Exception):
+    "Raised when the key types of two tables do not match, like VARCHAR and INT."

From 7865357760c4823a958ffafd224b32b5635b9355 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Fri, 12 Jan 2024 15:17:26 -0700
Subject: [PATCH 85/99] "date" should by type Date

---
 data_diff/databases/mssql.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index e4f841ef7..0beb32bdb 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -13,6 +13,7 @@
 )
 from data_diff.abcs.database_types import (
     JSON,
+    Date,
     NumericType,
     Timestamp,
     TimestampTZ,
@@ -46,7 +47,7 @@ class Dialect(BaseDialect):
         "datetime": Timestamp,
         "datetime2": Timestamp,
         "smalldatetime": Timestamp,
-        "date": Timestamp,
+        "date": Date,
         # Numbers
         "float": Float,
         "real": Float,

From 1fbc008da5f302ccd34409f0350361f1b8cdc9e3 Mon Sep 17 00:00:00 2001
From: Dan <daniel@datafold.com>
Date: Fri, 12 Jan 2024 16:17:42 -0700
Subject: [PATCH 86/99] add date type for databricks

---
 data_diff/databases/databricks.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index c3e40123d..36c74b64a 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -5,6 +5,7 @@
 import attrs
 
 from data_diff.abcs.database_types import (
+    Date,
     Integer,
     Float,
     Decimal,
@@ -52,6 +53,7 @@ class Dialect(BaseDialect):
         # Timestamps
         "TIMESTAMP": Timestamp,
         "TIMESTAMP_NTZ": Timestamp,
+        "DATE": Date,
         # Text
         "STRING": Text,
         "VARCHAR": Text,

From edad8e2ed7dcc353d9ecf41689941b49dc539ba1 Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Sun, 14 Jan 2024 12:48:05 +1100
Subject: [PATCH 87/99] Fix snowflake date formatting

---
 data_diff/databases/snowflake.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/data_diff/databases/snowflake.py b/data_diff/databases/snowflake.py
index 823ae5b29..2977239c7 100644
--- a/data_diff/databases/snowflake.py
+++ b/data_diff/databases/snowflake.py
@@ -81,6 +81,13 @@ def md5_as_hex(self, s: str) -> str:
         return f"md5({s})"
 
     def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
+        try:
+            is_date = coltype.is_date
+        except:
+            is_date = False
+        if isinstance(coltype, Date) or is_date:
+            return f"({value}::varchar)"
+
         if coltype.rounds:
             timestamp = f"to_timestamp(round(date_part(epoch_nanosecond, convert_timezone('UTC', {value})::timestamp(9))/1000000000, {coltype.precision}))"
         else:

From 54d6f2c069c4ab64e8fab8f58a05ba16ef89528f Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Sun, 14 Jan 2024 16:37:10 +1100
Subject: [PATCH 88/99] gFix date/time formatting for snowlake, postres and
 bigquery

---
 data_diff/abcs/database_types.py  |  5 +++++
 data_diff/databases/bigquery.py   | 19 +++++++++++++++++++
 data_diff/databases/mssql.py      |  4 +++-
 data_diff/databases/postgresql.py | 20 ++++++++++++++++++++
 data_diff/databases/snowflake.py  | 10 ++++++++++
 5 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/data_diff/abcs/database_types.py b/data_diff/abcs/database_types.py
index 1c40883d5..2860d2149 100644
--- a/data_diff/abcs/database_types.py
+++ b/data_diff/abcs/database_types.py
@@ -156,6 +156,11 @@ class Date(TemporalType):
     pass
 
 
+@attrs.define(frozen=True)
+class Time(TemporalType):
+    pass
+
+
 @attrs.define(frozen=True)
 class NumericType(ColType):
     # 'precision' signifies how many fractional digits (after the dot) we want to compare
diff --git a/data_diff/databases/bigquery.py b/data_diff/databases/bigquery.py
index c4470ee69..2a8797e9d 100644
--- a/data_diff/databases/bigquery.py
+++ b/data_diff/databases/bigquery.py
@@ -19,6 +19,8 @@
     TemporalType,
     Boolean,
     UnknownColType,
+    Time,
+    Date,
 )
 from data_diff.databases.base import (
     BaseDialect,
@@ -63,6 +65,8 @@ class Dialect(BaseDialect):
         # Dates
         "TIMESTAMP": Timestamp,
         "DATETIME": Datetime,
+        "DATE": Date,
+        "TIME": Time,
         # Numbers
         "INT64": Integer,
         "INT32": Integer,
@@ -160,6 +164,21 @@ def md5_as_hex(self, s: str) -> str:
         return f"md5({s})"
 
     def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
+        try:
+            is_date = coltype.is_date
+            is_time = coltype.is_time
+        except:
+            is_date = False
+            is_time = False
+        if isinstance(coltype, Date) or is_date:
+            return f"FORMAT_DATE('%F', {value})"
+        if isinstance(coltype, Time) or is_time:
+            microseconds = f"TIME_DIFF( {value}, cast('00:00:00' as time), microsecond)"
+            rounded = f"ROUND({microseconds}, -6 + {coltype.precision})"
+            time_value = f"TIME_ADD(cast('00:00:00' as time), interval cast({rounded} as int64) microsecond)"
+            converted = f"FORMAT_TIME('%H:%M:%E6S', {time_value})"
+            return converted
+
         if coltype.rounds:
             timestamp = f"timestamp_micros(cast(round(unix_micros(cast({value} as timestamp))/1000000, {coltype.precision})*1000000 as int))"
             return f"FORMAT_TIMESTAMP('%F %H:%M:%E6S', {timestamp})"
diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index 0beb32bdb..caa1d0b2a 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -13,7 +13,6 @@
 )
 from data_diff.abcs.database_types import (
     JSON,
-    Date,
     NumericType,
     Timestamp,
     TimestampTZ,
@@ -25,6 +24,8 @@
     Native_UUID,
     Text,
     Boolean,
+    Date,
+    Time
 )
 
 
@@ -48,6 +49,7 @@ class Dialect(BaseDialect):
         "datetime2": Timestamp,
         "smalldatetime": Timestamp,
         "date": Date,
+        "time": Time,
         # Numbers
         "float": Float,
         "real": Float,
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 1ec34f4ce..631b5c490 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -17,6 +17,7 @@
     FractionalType,
     Boolean,
     Date,
+    Time
 )
 from data_diff.databases.base import BaseDialect, ThreadedDatabase, import_helper, ConnectError
 from data_diff.databases.base import (
@@ -57,6 +58,8 @@ class PostgresqlDialect(BaseDialect):
         "timestamp without time zone": Timestamp,
         "timestamp": Timestamp,
         "date": Date,
+        "time with time zone": Time,
+        "time without time zone": Time,
         # Numbers
         "double precision": Float,
         "real": Float,
@@ -111,6 +114,23 @@ def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
         def _add_padding(coltype: TemporalType, timestamp6: str):
             return f"RPAD(LEFT({timestamp6}, {TIMESTAMP_PRECISION_POS+coltype.precision}), {TIMESTAMP_PRECISION_POS+6}, '0')"
 
+        try:
+            is_date = coltype.is_date
+            is_time = coltype.is_time
+        except:
+            is_date = False
+            is_time = False
+
+        if isinstance(coltype, Date) or is_date:
+            return f"cast({value} as varchar)"
+
+        if isinstance(coltype, Time) or is_time:
+            seconds = f"EXTRACT( epoch from {value})"
+            rounded = f"ROUND({seconds},  {coltype.precision})"
+            time_value = f"CAST('00:00:00' as time) + make_interval(0, 0, 0, 0, 0, 0, {rounded})"  # 6th arg = seconds
+            converted = f"to_char({time_value}, 'hh24:mi:ss.ff6')"
+            return converted
+
         if coltype.rounds:
             # NULL value expected to return NULL after normalization
             null_case_begin = f"CASE WHEN {value} IS NULL THEN NULL ELSE "
diff --git a/data_diff/databases/snowflake.py b/data_diff/databases/snowflake.py
index 2977239c7..2081e3429 100644
--- a/data_diff/databases/snowflake.py
+++ b/data_diff/databases/snowflake.py
@@ -15,6 +15,7 @@
     DbPath,
     Boolean,
     Date,
+    Time,
 )
 from data_diff.databases.base import (
     BaseDialect,
@@ -45,6 +46,7 @@ class Dialect(BaseDialect):
         "TIMESTAMP_LTZ": Timestamp,
         "TIMESTAMP_TZ": TimestampTZ,
         "DATE": Date,
+        "TIME": Time,
         # Numbers
         "NUMBER": Decimal,
         "FLOAT": Float,
@@ -83,10 +85,18 @@ def md5_as_hex(self, s: str) -> str:
     def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
         try:
             is_date = coltype.is_date
+            is_time = coltype.is_time
         except:
             is_date = False
+            is_time = False
         if isinstance(coltype, Date) or is_date:
             return f"({value}::varchar)"
+        elif isinstance(coltype, Time) or is_time:
+            microseconds = f"TIMEDIFF(microsecond, cast('00:00:00' as time), {value})"
+            rounded = f"round({microseconds}, -6 + {coltype.precision})"
+            time_value = f"TIMEADD(microsecond, {rounded}, cast('00:00:00' as time))"
+            converted = f"TO_VARCHAR({time_value}, 'HH24:MI:SS.FF6')"
+            return converted
 
         if coltype.rounds:
             timestamp = f"to_timestamp(round(date_part(epoch_nanosecond, convert_timezone('UTC', {value})::timestamp(9))/1000000000, {coltype.precision}))"

From 65be7c64a88786b300c8a1cc9e101c77908f8455 Mon Sep 17 00:00:00 2001
From: Alexey Mikhaylov <alexey@datafold.com>
Date: Mon, 15 Jan 2024 23:55:46 +1100
Subject: [PATCH 89/99] Fix databricks date

---
 data_diff/databases/databricks.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/data_diff/databases/databricks.py b/data_diff/databases/databricks.py
index 36c74b64a..580de4894 100644
--- a/data_diff/databases/databricks.py
+++ b/data_diff/databases/databricks.py
@@ -92,7 +92,12 @@ def md5_as_hex(self, s: str) -> str:
 
     def normalize_timestamp(self, value: str, coltype: TemporalType) -> str:
         """Databricks timestamp contains no more than 6 digits in precision"""
-
+        try:
+            is_date = coltype.is_date
+        except:
+            is_date = False
+        if isinstance(coltype, Date) or is_date:
+            return f"date_format({value}, 'yyyy-MM-dd')"
         if coltype.rounds:
             # cast to timestamp due to unix_micros() requiring timestamp
             timestamp = f"cast(round(unix_micros(cast({value} as timestamp)) / 1000000, {coltype.precision}) * 1000000 as bigint)"

From d2161ccf6705d4e6cde6069a7e5d945a7c0f1a89 Mon Sep 17 00:00:00 2001
From: Sarad Mohanan <sarad.mohanan@gmail.com>
Date: Tue, 23 Jan 2024 02:21:26 +0530
Subject: [PATCH 90/99] closing connection once data diff is executed (#785)

* closing connection once data diff is executed

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* typo fix

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* moving database to with block

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* optimizing _data_diff function

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* bug fix

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* linter fixes

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* formating code

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* update CONTRIBUTING.md and cleanup ansi escape sequences

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* read postgres db config from common.CONN_STRINGS

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* defaulting postgres port

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* test

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* test for __main__

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* adding close db connection test

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* update test case

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* do not use shared connection

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* no connection sharing

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* no connection sharing

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* avoid list typing

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* Update tests/test_main.py

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Update tests/test_main.py

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Apply suggestions from code review

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* Update tests/test_database.py

Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* minor

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* merging 784

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

* remove redundant variable

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>

---------

Signed-off-by: Sarad Mohanan <sarad.mohanan@gmail.com>
Co-authored-by: Sung Won Chung <sungwonchung3@gmail.com>
---
 .gitignore                        |   4 +-
 CONTRIBUTING.md                   |  11 +-
 data_diff/__main__.py             | 361 ++++++++++++++++++------------
 data_diff/databases/base.py       |  17 +-
 data_diff/databases/mssql.py      |   2 +-
 data_diff/databases/postgresql.py |   7 +-
 data_diff/databases/vertica.py    |   3 +-
 tests/cloud/test_data_source.py   |   6 +-
 tests/common.py                   |  19 +-
 tests/test_database.py            | 160 +++++++------
 tests/test_main.py                | 249 +++++++++++++++++++++
 tests/test_postgresql.py          |  61 ++---
 12 files changed, 633 insertions(+), 267 deletions(-)
 create mode 100644 tests/test_main.py

diff --git a/.gitignore b/.gitignore
index 644d7186d..e1f0a901c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -149,4 +149,6 @@ benchmark_*.png
 .vscode
 
 # History
-.history
\ No newline at end of file
+.history
+
+docker-compose-local.yml
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 03eaed229..95b1e7cf6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -66,7 +66,7 @@ Make sure to update the appropriate `TEST_*_CONN_STRING`, so that it will be inc
 
 #### Run the tests
 
-You can run the tests with `unittest`.
+You can run the tests with `python -m unittest`.
 
 When running against multiple databases, the tests can take a long while.
 
@@ -111,6 +111,15 @@ $ poetry install # Install dependencies
 $ docker-compose up -d mysql postgres # run mysql and postgres dbs in background
 ```
 
+If you want to change the configuration of docker-compose and run the DB containers, copy docker-compose.yml into docker-compose-local.yml, make changes and run
+```shell-session
+$ cp docker-compose.yml docker-compose-local.yml
+$ docker-compose -f docker-compose-local.yml up -d mysql postgres # run mysql and postgres dbs in background
+ ```
+you will also have to set up `tests/local_settings.py` where `TEST_*_CONN_STRING` can be edited
+
+`docker-compose-local.yml` and `tests/local_settings.py` is git ignored so should not show up in git changes.
+
 [docker-compose]: https://docs.docker.com/compose/install/
 
 **3. Run Unit Tests**
diff --git a/data_diff/__main__.py b/data_diff/__main__.py
index 02f3b31d1..ffd9bfa79 100644
--- a/data_diff/__main__.py
+++ b/data_diff/__main__.py
@@ -1,34 +1,32 @@
-from copy import deepcopy
-from datetime import datetime
+import json
+import logging
 import os
 import sys
 import time
-import json
-import logging
+from copy import deepcopy
+from datetime import datetime
 from itertools import islice
-from typing import Dict, Optional, Tuple
+from typing import Dict, Optional, Tuple, Union, List, Set
 
+import click
 import rich
 from rich.logging import RichHandler
-import click
 
 from data_diff import Database, DbPath
-from data_diff.schema import RawColumnInfo, create_schema
-from data_diff.queries.api import current_timestamp
-
+from data_diff.config import apply_config_from_file
+from data_diff.databases._connect import connect
 from data_diff.dbt import dbt_diff
-from data_diff.utils import eval_name_template, remove_password_from_url, safezip, match_like, LogStatusHandler
-from data_diff.diff_tables import Algorithm
+from data_diff.diff_tables import Algorithm, TableDiffer
 from data_diff.hashdiff_tables import HashDiffer, DEFAULT_BISECTION_THRESHOLD, DEFAULT_BISECTION_FACTOR
 from data_diff.joindiff_tables import TABLE_WRITE_LIMIT, JoinDiffer
-from data_diff.table_segment import TableSegment
-from data_diff.databases._connect import connect
 from data_diff.parse_time import parse_time_before, UNITS_STR, ParseError
-from data_diff.config import apply_config_from_file
+from data_diff.queries.api import current_timestamp
+from data_diff.schema import RawColumnInfo, create_schema
+from data_diff.table_segment import TableSegment
 from data_diff.tracking import disable_tracking, set_entrypoint_name
+from data_diff.utils import eval_name_template, remove_password_from_url, safezip, match_like, LogStatusHandler
 from data_diff.version import __version__
 
-
 COLOR_SCHEME = {
     "+": "green",
     "-": "red",
@@ -347,6 +345,144 @@ def main(conf, run, **kw) -> None:
         raise
 
 
+def _get_dbs(
+    threads: int, database1: str, threads1: int, database2: str, threads2: int, interactive: bool
+) -> Tuple[Database, Database]:
+    db1 = connect(database1, threads1 or threads)
+    if database1 == database2:
+        db2 = db1
+    else:
+        db2 = connect(database2, threads2 or threads)
+
+    if interactive:
+        db1.enable_interactive()
+        db2.enable_interactive()
+
+    return db1, db2
+
+
+def _set_age(options: dict, min_age: Optional[str], max_age: Optional[str], db: Database) -> None:
+    if min_age or max_age:
+        now: datetime = db.query(current_timestamp(), datetime).replace(tzinfo=None)
+        try:
+            if max_age:
+                options["min_update"] = parse_time_before(now, max_age)
+            if min_age:
+                options["max_update"] = parse_time_before(now, min_age)
+        except ParseError as e:
+            logging.error(f"Error while parsing age expression: {e}")
+
+
+def _get_table_differ(
+    algorithm: str,
+    db1: Database,
+    db2: Database,
+    threaded: bool,
+    threads: int,
+    assume_unique_key: bool,
+    sample_exclusive_rows: bool,
+    materialize_all_rows: bool,
+    table_write_limit: int,
+    materialize_to_table: Optional[str],
+    bisection_factor: Optional[int],
+    bisection_threshold: Optional[int],
+) -> TableDiffer:
+    algorithm = Algorithm(algorithm)
+    if algorithm == Algorithm.AUTO:
+        algorithm = Algorithm.JOINDIFF if db1 == db2 else Algorithm.HASHDIFF
+
+    logging.info(f"Using algorithm '{algorithm.name.lower()}'.")
+
+    if algorithm == Algorithm.JOINDIFF:
+        return JoinDiffer(
+            threaded=threaded,
+            max_threadpool_size=threads and threads * 2,
+            validate_unique_key=not assume_unique_key,
+            sample_exclusive_rows=sample_exclusive_rows,
+            materialize_all_rows=materialize_all_rows,
+            table_write_limit=table_write_limit,
+            materialize_to_table=(
+                materialize_to_table and db1.dialect.parse_table_name(eval_name_template(materialize_to_table))
+            ),
+        )
+
+    assert algorithm == Algorithm.HASHDIFF
+    return HashDiffer(
+        bisection_factor=DEFAULT_BISECTION_FACTOR if bisection_factor is None else bisection_factor,
+        bisection_threshold=DEFAULT_BISECTION_THRESHOLD if bisection_threshold is None else bisection_threshold,
+        threaded=threaded,
+        max_threadpool_size=threads and threads * 2,
+    )
+
+
+def _print_result(stats, json_output, diff_iter) -> None:
+    if stats:
+        if json_output:
+            rich.print(json.dumps(diff_iter.get_stats_dict()))
+        else:
+            rich.print(diff_iter.get_stats_string())
+
+    else:
+        for op, values in diff_iter:
+            color = COLOR_SCHEME.get(op, "grey62")
+
+            if json_output:
+                jsonl = json.dumps([op, list(values)])
+                rich.print(f"[{color}]{jsonl}[/{color}]")
+            else:
+                text = f"{op} {', '.join(map(str, values))}"
+                rich.print(f"[{color}]{text}[/{color}]")
+
+            sys.stdout.flush()
+
+
+def _get_expanded_columns(
+    columns: List[str],
+    case_sensitive: bool,
+    mutual: Set[str],
+    db1: Database,
+    schema1: dict,
+    table1: str,
+    db2: Database,
+    schema2: dict,
+    table2: str,
+) -> Set[str]:
+    expanded_columns: Set[str] = set()
+    for c in columns:
+        cc = c if case_sensitive else c.lower()
+        match = set(match_like(cc, mutual))
+        if not match:
+            m1 = None if any(match_like(cc, schema1.keys())) else f"{db1}/{table1}"
+            m2 = None if any(match_like(cc, schema2.keys())) else f"{db2}/{table2}"
+            not_matched = ", ".join(m for m in [m1, m2] if m)
+            raise ValueError(f"Column '{c}' not found in: {not_matched}")
+
+        expanded_columns |= match
+    return expanded_columns
+
+
+def _get_threads(threads: Union[int, str, None], threads1: Optional[int], threads2: Optional[int]) -> Tuple[bool, int]:
+    threaded = True
+    if threads is None:
+        threads = 1
+    elif isinstance(threads, str) and threads.lower() == "serial":
+        assert not (threads1 or threads2)
+        threaded = False
+        threads = 1
+    else:
+        try:
+            threads = int(threads)
+        except ValueError:
+            logging.error("Error: threads must be a number, or 'serial'.")
+            raise
+
+        if threads < 1:
+            logging.error("Error: threads must be >= 1")
+            raise ValueError("Error: threads must be >= 1")
+
+    return threaded, threads
+
+
 def _data_diff(
     database1,
     table1,
@@ -393,26 +529,7 @@ def _data_diff(
         return
 
     key_columns = key_columns or ("id",)
-    bisection_factor = DEFAULT_BISECTION_FACTOR if bisection_factor is None else int(bisection_factor)
-    bisection_threshold = DEFAULT_BISECTION_THRESHOLD if bisection_threshold is None else int(bisection_threshold)
-
-    threaded = True
-    if threads is None:
-        threads = 1
-    elif isinstance(threads, str) and threads.lower() == "serial":
-        assert not (threads1 or threads2)
-        threaded = False
-        threads = 1
-    else:
-        try:
-            threads = int(threads)
-        except ValueError:
-            logging.error("Error: threads must be a number, or 'serial'.")
-            return
-        if threads < 1:
-            logging.error("Error: threads must be >= 1")
-            return
-
+    threaded, threads = _get_threads(threads, threads1, threads2)
     start = time.monotonic()
 
     if database1 is None or database2 is None:
@@ -421,133 +538,79 @@ def _data_diff(
         )
         return
 
-    db1 = connect(database1, threads1 or threads)
-    if database1 == database2:
-        db2 = db1
-    else:
-        db2 = connect(database2, threads2 or threads)
-
-    options = dict(
-        case_sensitive=case_sensitive,
-        where=where,
-    )
-
-    if min_age or max_age:
-        now: datetime = db1.query(current_timestamp(), datetime)
-        now = now.replace(tzinfo=None)
-        try:
-            if max_age:
-                options["min_update"] = parse_time_before(now, max_age)
-            if min_age:
-                options["max_update"] = parse_time_before(now, min_age)
-        except ParseError as e:
-            logging.error(f"Error while parsing age expression: {e}")
-            return
-
-    dbs: Tuple[Database, Database] = db1, db2
-
-    if interactive:
-        for db in dbs:
-            db.enable_interactive()
-
-    algorithm = Algorithm(algorithm)
-    if algorithm == Algorithm.AUTO:
-        algorithm = Algorithm.JOINDIFF if db1 == db2 else Algorithm.HASHDIFF
-
-    if algorithm == Algorithm.JOINDIFF:
-        differ = JoinDiffer(
-            threaded=threaded,
-            max_threadpool_size=threads and threads * 2,
-            validate_unique_key=not assume_unique_key,
-            sample_exclusive_rows=sample_exclusive_rows,
-            materialize_all_rows=materialize_all_rows,
-            table_write_limit=table_write_limit,
-            materialize_to_table=materialize_to_table
-            and db1.dialect.parse_table_name(eval_name_template(materialize_to_table)),
-        )
-    else:
-        assert algorithm == Algorithm.HASHDIFF
-        differ = HashDiffer(
-            bisection_factor=bisection_factor,
-            bisection_threshold=bisection_threshold,
-            threaded=threaded,
-            max_threadpool_size=threads and threads * 2,
+    db1: Database
+    db2: Database
+    db1, db2 = _get_dbs(threads, database1, threads1, database2, threads2, interactive)
+    with db1, db2:
+        options = {
+            "case_sensitive": case_sensitive,
+            "where": where,
+        }
+
+        _set_age(options, min_age, max_age, db1)
+        dbs: Tuple[Database, Database] = db1, db2
+
+        differ = _get_table_differ(
+            algorithm,
+            db1,
+            db2,
+            threaded,
+            threads,
+            assume_unique_key,
+            sample_exclusive_rows,
+            materialize_all_rows,
+            table_write_limit,
+            materialize_to_table,
+            bisection_factor,
+            bisection_threshold,
         )
 
-    table_names = table1, table2
-    table_paths = [db.dialect.parse_table_name(t) for db, t in safezip(dbs, table_names)]
+        table_names = table1, table2
+        table_paths = [db.dialect.parse_table_name(t) for db, t in safezip(dbs, table_names)]
 
-    schemas = list(differ._thread_map(_get_schema, safezip(dbs, table_paths)))
-    schema1, schema2 = schemas = [
-        create_schema(db.name, table_path, schema, case_sensitive)
-        for db, table_path, schema in safezip(dbs, table_paths, schemas)
-    ]
+        schemas = list(differ._thread_map(_get_schema, safezip(dbs, table_paths)))
+        schema1, schema2 = schemas = [
+            create_schema(db.name, table_path, schema, case_sensitive)
+            for db, table_path, schema in safezip(dbs, table_paths, schemas)
+        ]
 
-    mutual = schema1.keys() & schema2.keys()  # Case-aware, according to case_sensitive
-    logging.debug(f"Available mutual columns: {mutual}")
-
-    expanded_columns = set()
-    for c in columns:
-        cc = c if case_sensitive else c.lower()
-        match = set(match_like(cc, mutual))
-        if not match:
-            m1 = None if any(match_like(cc, schema1.keys())) else f"{db1}/{table1}"
-            m2 = None if any(match_like(cc, schema2.keys())) else f"{db2}/{table2}"
-            not_matched = ", ".join(m for m in [m1, m2] if m)
-            raise ValueError(f"Column '{c}' not found in: {not_matched}")
+        mutual = schema1.keys() & schema2.keys()  # Case-aware, according to case_sensitive
+        logging.debug(f"Available mutual columns: {mutual}")
 
-        expanded_columns |= match
-
-    columns = tuple(expanded_columns - {*key_columns, update_column})
-
-    if db1 == db2:
-        diff_schemas(
-            table_names[0],
-            table_names[1],
-            schema1,
-            schema2,
-            (
-                *key_columns,
-                update_column,
-                *columns,
-            ),
+        expanded_columns = _get_expanded_columns(
+            columns, case_sensitive, mutual, db1, schema1, table1, db2, schema2, table2
         )
+        columns = tuple(expanded_columns - {*key_columns, update_column})
+
+        if db1 == db2:
+            diff_schemas(
+                table_names[0],
+                table_names[1],
+                schema1,
+                schema2,
+                (
+                    *key_columns,
+                    update_column,
+                    *columns,
+                ),
+            )
 
-    logging.info(f"Diffing using columns: key={key_columns} update={update_column} extra={columns}.")
-    logging.info(f"Using algorithm '{algorithm.name.lower()}'.")
-
-    segments = [
-        TableSegment(db, table_path, key_columns, update_column, columns, **options)._with_raw_schema(raw_schema)
-        for db, table_path, raw_schema in safezip(dbs, table_paths, schemas)
-    ]
-
-    diff_iter = differ.diff_tables(*segments)
-
-    if limit:
-        assert not stats
-        diff_iter = islice(diff_iter, int(limit))
+        logging.info(f"Diffing using columns: key={key_columns} update={update_column} extra={columns}.")
 
-    if stats:
-        if json_output:
-            rich.print(json.dumps(diff_iter.get_stats_dict()))
-        else:
-            rich.print(diff_iter.get_stats_string())
+        segments = [
+            TableSegment(db, table_path, key_columns, update_column, columns, **options)._with_raw_schema(raw_schema)
+            for db, table_path, raw_schema in safezip(dbs, table_paths, schemas)
+        ]
 
-    else:
-        for op, values in diff_iter:
-            color = COLOR_SCHEME.get(op, "grey62")
+        diff_iter = differ.diff_tables(*segments)
 
-            if json_output:
-                jsonl = json.dumps([op, list(values)])
-                rich.print(f"[{color}]{jsonl}[/{color}]")
-            else:
-                text = f"{op} {', '.join(map(str, values))}"
-                rich.print(f"[{color}]{text}[/{color}]")
+        if limit:
+            assert not stats
+            diff_iter = islice(diff_iter, int(limit))
 
-            sys.stdout.flush()
+        _print_result(stats, json_output, diff_iter)
 
     end = time.monotonic()
-
     logging.info(f"Duration: {end-start:.2f} seconds.")
 
 
diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index d6549f714..8adea0b56 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -938,6 +938,12 @@ class Database(abc.ABC):
     is_closed: bool = False
     _dialect: BaseDialect = None
 
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exc_type, exc_value, traceback):
+        self.close()
+
     @property
     def name(self):
         return type(self).__name__
@@ -1058,7 +1064,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
         return d
 
     def select_table_unique_columns(self, path: DbPath) -> str:
-        "Provide SQL for selecting the names of unique columns in the table"
+        """Provide SQL for selecting the names of unique columns in the table"""
         schema, name = self._normalize_table_path(path)
 
         return (
@@ -1180,9 +1186,8 @@ def _query_conn(self, conn, sql_code: Union[str, ThreadLocalInterpreter]) -> Que
         return apply_query(callback, sql_code)
 
     def close(self):
-        "Close connection(s) to the database instance. Querying will stop functioning."
+        """Close connection(s) to the database instance. Querying will stop functioning."""
         self.is_closed = True
-        return super().close()
 
     @property
     def dialect(self) -> BaseDialect:
@@ -1241,18 +1246,20 @@ def _query(self, sql_code: Union[str, ThreadLocalInterpreter]) -> QueryResult:
         return r.result()
 
     def _query_in_worker(self, sql_code: Union[str, ThreadLocalInterpreter]):
-        "This method runs in a worker thread"
+        """This method runs in a worker thread"""
         if self._init_error:
             raise self._init_error
         return self._query_conn(self.thread_local.conn, sql_code)
 
     @abstractmethod
     def create_connection(self):
-        "Return a connection instance, that supports the .cursor() method."
+        """Return a connection instance, that supports the .cursor() method."""
 
     def close(self):
         super().close()
         self._queue.shutdown()
+        if hasattr(self.thread_local, "conn"):
+            self.thread_local.conn.close()
 
     @property
     def is_autocommit(self) -> bool:
diff --git a/data_diff/databases/mssql.py b/data_diff/databases/mssql.py
index caa1d0b2a..59d8a49d6 100644
--- a/data_diff/databases/mssql.py
+++ b/data_diff/databases/mssql.py
@@ -25,7 +25,7 @@
     Text,
     Boolean,
     Date,
-    Time
+    Time,
 )
 
 
diff --git a/data_diff/databases/postgresql.py b/data_diff/databases/postgresql.py
index 631b5c490..d93a46d70 100644
--- a/data_diff/databases/postgresql.py
+++ b/data_diff/databases/postgresql.py
@@ -17,7 +17,7 @@
     FractionalType,
     Boolean,
     Date,
-    Time
+    Time,
 )
 from data_diff.databases.base import BaseDialect, ThreadedDatabase, import_helper, ConnectError
 from data_diff.databases.base import (
@@ -251,3 +251,8 @@ def _normalize_table_path(self, path: DbPath) -> DbPath:
         raise ValueError(
             f"{self.name}: Bad table path for {self}: '{'.'.join(path)}'. Expected format: table, schema.table, or database.schema.table"
         )
+
+    def close(self):
+        super().close()
+        if self._conn is not None:
+            self._conn.close()
diff --git a/data_diff/databases/vertica.py b/data_diff/databases/vertica.py
index cfe046d28..9b1de1f4d 100644
--- a/data_diff/databases/vertica.py
+++ b/data_diff/databases/vertica.py
@@ -146,8 +146,7 @@ def __init__(self, *, thread_count, **kw) -> None:
     def create_connection(self):
         vertica = import_vertica()
         try:
-            c = vertica.connect(**self._args)
-            return c
+            return vertica.connect(**self._args)
         except vertica.errors.ConnectionError as e:
             raise ConnectError(*e.args) from e
 
diff --git a/tests/cloud/test_data_source.py b/tests/cloud/test_data_source.py
index cc524a325..1e4a81297 100644
--- a/tests/cloud/test_data_source.py
+++ b/tests/cloud/test_data_source.py
@@ -22,7 +22,7 @@
     _test_data_source,
 )
 from data_diff.dbt_parser import TDatadiffConfig
-
+from tests.common import ansi_stdout_cleanup
 
 DATA_SOURCE_CONFIGS = {
     "snowflake": TDsConfig(
@@ -262,7 +262,7 @@ def test_create_ds_snowflake_config_from_dbt_profiles_one_param_passed_through_i
             )
             self.assertEqual(actual_config, config)
             self.assertEqual(
-                mock_stdout.getvalue().strip(),
+                ansi_stdout_cleanup(mock_stdout.getvalue().strip()),
                 'Cannot extract "account" from dbt profiles.yml. Please, type it manually',
             )
 
@@ -294,7 +294,7 @@ def test_create_ds_config_validate_required_parameter(self, mock_stdout):
                 data_source_name=config.name,
             )
             self.assertEqual(actual_config, config)
-            self.assertEqual(mock_stdout.getvalue().strip(), "Parameter must not be empty")
+            self.assertEqual(ansi_stdout_cleanup(mock_stdout.getvalue().strip()), "Parameter must not be empty")
 
     def test_check_data_source_exists(self):
         self.assertEqual(_check_data_source_exists(self.data_sources, self.data_sources[0].name), self.data_sources[0])
diff --git a/tests/common.py b/tests/common.py
index 2fc6be196..d6dd94e1e 100644
--- a/tests/common.py
+++ b/tests/common.py
@@ -1,5 +1,6 @@
 import hashlib
 import os
+import re
 import string
 import random
 from typing import Callable
@@ -84,15 +85,8 @@ def get_git_revision_short_hash() -> str:
     db.MsSQL: TEST_MSSQL_CONN_STRING,
 }
 
-_database_instances = {}
-
-
-def get_conn(cls: type, shared: bool = True) -> Database:
-    if shared:
-        if cls not in _database_instances:
-            _database_instances[cls] = get_conn(cls, shared=False)
-        return _database_instances[cls]
 
+def get_conn(cls: type) -> Database:
     return connect(CONN_STRINGS[cls], N_THREADS)
 
 
@@ -134,17 +128,16 @@ def str_to_checksum(str: str):
 
 
 class DiffTestCase(unittest.TestCase):
-    "Sets up two tables for diffing"
+    """Sets up two tables for diffing"""
 
     db_cls = None
     src_schema = None
     dst_schema = None
-    shared_connection = True
 
     def setUp(self):
         assert self.db_cls, self.db_cls
 
-        self.connection = get_conn(self.db_cls, self.shared_connection)
+        self.connection = get_conn(self.db_cls)
 
         table_suffix = random_table_suffix()
         self.table_src_name = f"src{table_suffix}"
@@ -187,3 +180,7 @@ def table_segment(database, table_path, key_columns, *args, **kw):
     if isinstance(key_columns, str):
         key_columns = (key_columns,)
     return TableSegment(database, table_path, key_columns, *args, **kw)
+
+
+def ansi_stdout_cleanup(ansi_input) -> str:
+    return re.sub(r"\x1B\[[0-?]*[ -/]*[@-~]", "", ansi_input)
diff --git a/tests/test_database.py b/tests/test_database.py
index 2713ac16d..f5055ce78 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -5,8 +5,9 @@
 import attrs
 import pytz
 
-from data_diff import connect
+from data_diff import connect, Database
 from data_diff import databases as dbs
+from data_diff.abcs.database_types import TimestampTZ
 from data_diff.queries.api import table, current_timestamp
 from data_diff.queries.extras import NormalizeAsString
 from data_diff.schema import create_schema
@@ -17,7 +18,6 @@
     str_to_checksum,
     random_table_suffix,
 )
-from data_diff.abcs.database_types import TimestampTZ
 
 TEST_DATABASES = {
     dbs.MySQL,
@@ -48,11 +48,11 @@ class TestMD5(unittest.TestCase):
     def test_md5_as_int(self):
         self.mysql = connect(TEST_MYSQL_CONN_STRING)
 
-        str = "hello world"
-        query_fragment = self.mysql.dialect.md5_as_int("'{0}'".format(str))
+        message = "hello world"
+        query_fragment = self.mysql.dialect.md5_as_int(f"'{message}'")
         query = f"SELECT {query_fragment}"
 
-        self.assertEqual(str_to_checksum(str), self.mysql.query(query, int))
+        self.assertEqual(str_to_checksum(message), self.mysql.query(query, int))
 
 
 class TestConnect(unittest.TestCase):
@@ -74,42 +74,48 @@ def test_correct_timezone(self):
         if self.db_cls in [dbs.MsSQL]:
             self.skipTest("No support for session tz.")
         name = "tbl_" + random_table_suffix()
-        db = get_conn(self.db_cls)
-        tbl = table(name, schema={"id": int, "created_at": TimestampTZ(9), "updated_at": TimestampTZ(9)})
 
-        db.query(tbl.create())
+        db_connection = get_conn(self.db_cls)
+        with db_connection:
+            tbl = table(name, schema={"id": int, "created_at": TimestampTZ(9), "updated_at": TimestampTZ(9)})
+
+            db_connection.query(tbl.create())
 
-        tz = pytz.timezone("Europe/Berlin")
+            tz = pytz.timezone("Europe/Berlin")
 
-        now = datetime.now(tz)
-        if isinstance(db, dbs.Presto):
-            ms = now.microsecond // 1000 * 1000  # Presto max precision is 3
-            now = now.replace(microsecond=ms)
+            now = datetime.now(tz)
+            if isinstance(db_connection, dbs.Presto):
+                ms = now.microsecond // 1000 * 1000  # Presto max precision is 3
+                now = now.replace(microsecond=ms)
 
-        db.query(table(name).insert_row(1, now, now))
-        db.query(db.dialect.set_timezone_to_utc())
+            db_connection.query(table(name).insert_row(1, now, now))
+            db_connection.query(db_connection.dialect.set_timezone_to_utc())
 
-        t = table(name)
-        raw_schema = db.query_table_schema(t.path)
-        schema = db._process_table_schema(t.path, raw_schema)
-        schema = create_schema(db.name, t, schema, case_sensitive=True)
-        t = attrs.evolve(t, schema=schema)
-        t.schema["created_at"] = attrs.evolve(t.schema["created_at"], precision=t.schema["created_at"].precision)
+            table_object = table(name)
+            raw_schema = db_connection.query_table_schema(table_object.path)
+            schema = db_connection._process_table_schema(table_object.path, raw_schema)
+            schema = create_schema(db_connection.name, table_object, schema, case_sensitive=True)
+            table_object = attrs.evolve(table_object, schema=schema)
+            table_object.schema["created_at"] = attrs.evolve(
+                table_object.schema["created_at"], precision=table_object.schema["created_at"].precision
+            )
 
-        tbl = table(name, schema=t.schema)
+            tbl = table(name, schema=table_object.schema)
 
-        results = db.query(tbl.select(NormalizeAsString(tbl[c]) for c in ["created_at", "updated_at"]), List[Tuple])
+            results = db_connection.query(
+                tbl.select(NormalizeAsString(tbl[c]) for c in ["created_at", "updated_at"]), List[Tuple]
+            )
 
-        created_at = results[0][1]
-        updated_at = results[0][1]
+            created_at = results[0][1]
+            updated_at = results[0][1]
 
-        utc = now.astimezone(pytz.UTC)
-        expected = utc.__format__("%Y-%m-%d %H:%M:%S.%f")
+            utc = now.astimezone(pytz.UTC)
+            expected = utc.__format__("%Y-%m-%d %H:%M:%S.%f")
 
-        self.assertEqual(created_at, expected)
-        self.assertEqual(updated_at, expected)
+            self.assertEqual(created_at, expected)
+            self.assertEqual(updated_at, expected)
 
-        db.query(tbl.drop())
+            db_connection.query(tbl.drop())
 
 
 @test_each_database
@@ -119,51 +125,77 @@ def test_three_part_support(self):
             self.skipTest("Limited support for 3 part ids")
 
         table_name = "tbl_" + random_table_suffix()
-        db = get_conn(self.db_cls)
-        db_res = db.query(f"SELECT {db.dialect.current_database()}")
-        schema_res = db.query(f"SELECT {db.dialect.current_schema()}")
-        db_name = db_res.rows[0][0]
-        schema_name = schema_res.rows[0][0]
+        db_connection = get_conn(self.db_cls)
+        with db_connection:
+            db_res = db_connection.query(f"SELECT {db_connection.dialect.current_database()}")
+            schema_res = db_connection.query(f"SELECT {db_connection.dialect.current_schema()}")
+            db_name = db_res.rows[0][0]
+            schema_name = schema_res.rows[0][0]
 
-        table_one_part = table((table_name,), schema={"id": int})
-        table_two_part = table((schema_name, table_name), schema={"id": int})
-        table_three_part = table((db_name, schema_name, table_name), schema={"id": int})
+            table_one_part = table((table_name,), schema={"id": int})
+            table_two_part = table((schema_name, table_name), schema={"id": int})
+            table_three_part = table((db_name, schema_name, table_name), schema={"id": int})
 
-        for part in (table_one_part, table_two_part, table_three_part):
-            db.query(part.create())
-            d = db.query_table_schema(part.path)
-            assert len(d) == 1
-            db.query(part.drop())
+            for part in (table_one_part, table_two_part, table_three_part):
+                db_connection.query(part.create())
+                schema = db_connection.query_table_schema(part.path)
+                assert len(schema) == 1
+                db_connection.query(part.drop())
 
 
 @test_each_database
 class TestNumericPrecisionParsing(unittest.TestCase):
     def test_specified_precision(self):
         name = "tbl_" + random_table_suffix()
-        db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "DECIMAL(10, 2)"})
-        db.query(tbl.create())
-        t = table(name)
-        raw_schema = db.query_table_schema(t.path)
-        schema = db._process_table_schema(t.path, raw_schema)
-        self.assertEqual(schema["value"].precision, 2)
+        db_connection = get_conn(self.db_cls)
+        with db_connection:
+            table_object = table(name, schema={"value": "DECIMAL(10, 2)"})
+            db_connection.query(table_object.create())
+            table_object = table(name)
+            raw_schema = db_connection.query_table_schema(table_object.path)
+            schema = db_connection._process_table_schema(table_object.path, raw_schema)
+            self.assertEqual(schema["value"].precision, 2)
 
     def test_specified_zero_precision(self):
         name = "tbl_" + random_table_suffix()
-        db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "DECIMAL(10)"})
-        db.query(tbl.create())
-        t = table(name)
-        raw_schema = db.query_table_schema(t.path)
-        schema = db._process_table_schema(t.path, raw_schema)
-        self.assertEqual(schema["value"].precision, 0)
+        db_connection = get_conn(self.db_cls)
+        with db_connection:
+            table_object = table(name, schema={"value": "DECIMAL(10)"})
+            db_connection.query(table_object.create())
+            table_object = table(name)
+            raw_schema = db_connection.query_table_schema(table_object.path)
+            schema = db_connection._process_table_schema(table_object.path, raw_schema)
+            self.assertEqual(schema["value"].precision, 0)
 
     def test_default_precision(self):
         name = "tbl_" + random_table_suffix()
-        db = get_conn(self.db_cls)
-        tbl = table(name, schema={"value": "DECIMAL"})
-        db.query(tbl.create())
-        t = table(name)
-        raw_schema = db.query_table_schema(t.path)
-        schema = db._process_table_schema(t.path, raw_schema)
-        self.assertEqual(schema["value"].precision, db.dialect.DEFAULT_NUMERIC_PRECISION)
+        db_connection = get_conn(self.db_cls)
+        with db_connection:
+            table_object = table(name, schema={"value": "DECIMAL"})
+            db_connection.query(table_object.create())
+            table_object = table(name)
+            raw_schema = db_connection.query_table_schema(table_object.path)
+            schema = db_connection._process_table_schema(table_object.path, raw_schema)
+            self.assertEqual(schema["value"].precision, db_connection.dialect.DEFAULT_NUMERIC_PRECISION)
+
+
+# Skip presto as it doesn't support a close method:
+# https://github.com/prestodb/presto-python-client/blob/be2610e524fa8400c9f2baa41ba0159d44ac2b11/prestodb/dbapi.py#L130
+closeable_databases = TEST_DATABASES.copy()
+closeable_databases.discard(dbs.Presto)
+
+test_closeable_databases: Callable = test_each_database_in_list(closeable_databases)
+
+
+@test_closeable_databases
+class TestCloseMethod(unittest.TestCase):
+    def test_close_connection(self):
+        database: Database = get_conn(self.db_cls)
+
+        # Perform a query to verify the connection is established
+        with database:
+            database.query("SELECT 1")
+
+        # Now the connection should be closed, and trying to execute a query should fail.
+        with self.assertRaises(Exception):  # Catch any type of exception.
+            database.query("SELECT 1")
diff --git a/tests/test_main.py b/tests/test_main.py
new file mode 100644
index 000000000..cc1333cba
--- /dev/null
+++ b/tests/test_main.py
@@ -0,0 +1,249 @@
+import unittest
+
+from data_diff import Database, JoinDiffer, HashDiffer
+from data_diff import databases as db
+from data_diff.__main__ import _get_dbs, _set_age, _get_table_differ, _get_expanded_columns, _get_threads
+from data_diff.databases.mysql import MySQL
+from data_diff.diff_tables import TableDiffer
+from tests.common import CONN_STRINGS, get_conn, DiffTestCase
+
+
+class TestGetDBS(unittest.TestCase):
+    def test__get_dbs(self) -> None:
+        db1: Database
+        db2: Database
+        db1_str: str = CONN_STRINGS[db.PostgreSQL]
+        db2_str: str = CONN_STRINGS[db.PostgreSQL]
+
+        # no threads and 2 threads1
+        db1, db2 = _get_dbs(0, db1_str, 2, db2_str, 0, False)
+        with db1, db2:
+            assert db1 == db2
+            assert db1.thread_count == 2
+
+        # 3 threads and 0 threads1
+        db1, db2 = _get_dbs(3, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 == db2
+            assert db1.thread_count == 3
+
+        # not interactive
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 == db2
+            assert not db1._interactive
+
+        # interactive
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, True)
+        with db1, db2:
+            assert db1 == db2
+            assert db1._interactive
+
+        db2_str: str = CONN_STRINGS[db.MySQL]
+
+        # no threads and 1 threads1 and 2 thread2
+        db1, db2 = _get_dbs(0, db1_str, 1, db2_str, 2, False)
+        with db1, db2:
+            assert db1 != db2
+            assert db1.thread_count == 1
+            assert db2.thread_count == 2
+
+        # 3 threads and 0 threads1 and 0 thread2
+        db1, db2 = _get_dbs(3, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 != db2
+            assert db1.thread_count == 3
+            assert db2.thread_count == 3
+            assert db1.thread_count == db2.thread_count
+
+        # not interactive
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 != db2
+            assert not db1._interactive
+            assert not db2._interactive
+
+        # interactive
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, True)
+        with db1, db2:
+            assert db1 != db2
+            assert db1._interactive
+            assert db2._interactive
+
+    def test_database_connection_failure(self) -> None:
+        """Test when database connection fails."""
+        with self.assertRaises(Exception):  # Assuming that connect() raises Exception on connection failure
+            _get_dbs(1, "db1_str", 0, "db2_str", 0, False)
+
+    def test_invalid_inputs(self) -> None:
+        """Test invalid inputs."""
+        with self.assertRaises(Exception):  # Assuming that connect() raises Exception on failure
+            _get_dbs(0, "", 0, "", 0, False)  # Empty connection strings
+
+    def test_database_object(self) -> None:
+        """Test returned database objects are valid and not None."""
+        db1_str: str = CONN_STRINGS[db.PostgreSQL]
+        db2_str: str = CONN_STRINGS[db.PostgreSQL]
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, False)
+        self.assertIsNotNone(db1)
+        self.assertIsNotNone(db2)
+        self.assertIsInstance(db1, Database)
+        self.assertIsInstance(db2, Database)
+
+    def test_databases_are_different(self) -> None:
+        """Test separate connections for different databases."""
+        db1_str: str = CONN_STRINGS[db.PostgreSQL]
+        db2_str: str = CONN_STRINGS[db.MySQL]
+        db1, db2 = _get_dbs(0, db1_str, 1, db2_str, 2, False)
+        with db1, db2:
+            self.assertIsNot(db1, db2)  # Check that db1 and db2 are not the same object
+
+
+class TestSetAge(unittest.TestCase):
+    def setUp(self) -> None:
+        self.database: Database = get_conn(db.PostgreSQL)
+
+    def tearDown(self):
+        self.database.close()
+
+    def test__set_age(self):
+        options = {}
+        _set_age(options, None, None, self.database)
+        assert len(options) == 0
+
+        options = {}
+        _set_age(options, "1d", None, self.database)
+        assert len(options) == 1
+        assert options.get("max_update") is not None
+
+        options = {}
+        _set_age(options, None, "1d", self.database)
+        assert len(options) == 1
+        assert options.get("min_update") is not None
+
+        options = {}
+        _set_age(options, "1d", "1d", self.database)
+        assert len(options) == 2
+        assert options.get("max_update") is not None
+        assert options.get("min_update") is not None
+
+    def test__set_age_db_query_failure(self):
+        with self.assertRaises(Exception):
+            options = {}
+            _set_age(options, "1d", "1d", self.mock_database)
+
+
+class TestGetTableDiffer(unittest.TestCase):
+    def test__get_table_differ(self):
+        db1: Database
+        db2: Database
+        db1_str: str = CONN_STRINGS[db.PostgreSQL]
+        db2_str: str = CONN_STRINGS[db.PostgreSQL]
+
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 == db2
+            table_differ: TableDiffer = self._get_differ("auto", db1, db2)
+            assert isinstance(table_differ, JoinDiffer)
+
+            table_differ: TableDiffer = self._get_differ("joindiff", db1, db2)
+            assert isinstance(table_differ, JoinDiffer)
+
+            table_differ: TableDiffer = self._get_differ("hashdiff", db1, db2)
+            assert isinstance(table_differ, HashDiffer)
+
+        db2_str: str = CONN_STRINGS[db.MySQL]
+        db1, db2 = _get_dbs(1, db1_str, 0, db2_str, 0, False)
+        with db1, db2:
+            assert db1 != db2
+            table_differ: TableDiffer = self._get_differ("auto", db1, db2)
+            assert isinstance(table_differ, HashDiffer)
+
+            table_differ: TableDiffer = self._get_differ("joindiff", db1, db2)
+            assert isinstance(table_differ, JoinDiffer)
+
+            table_differ: TableDiffer = self._get_differ("hashdiff", db1, db2)
+            assert isinstance(table_differ, HashDiffer)
+
+    @staticmethod
+    def _get_differ(algorithm, db1, db2):
+        return _get_table_differ(algorithm, db1, db2, False, 1, False, False, False, 1, None, None, None)
+
+
+class TestGetExpandedColumns(DiffTestCase):
+    db_cls = MySQL
+
+    def setUp(self):
+        super().setUp()
+
+    def test__get_expanded_columns(self):
+        columns = ["user_id", "movie_id", "rating"]
+        kwargs = {
+            "db1": self.connection,
+            "schema1": self.src_schema,
+            "table1": self.table_src_name,
+            "db2": self.connection,
+            "schema2": self.dst_schema,
+            "table2": self.table_dst_name,
+        }
+        expanded_columns = _get_expanded_columns(columns, False, set(columns), **kwargs)
+
+        assert len(expanded_columns) == 3
+        assert len(set(expanded_columns) & set(columns)) == 3
+
+    def test__get_expanded_columns_case_sensitive(self):
+        columns = ["UserID", "MovieID", "Rating"]
+        kwargs = {
+            "db1": self.connection,
+            "schema1": self.src_schema,
+            "table1": self.table_src_name,
+            "db2": self.connection,
+            "schema2": self.dst_schema,
+            "table2": self.table_dst_name,
+        }
+        expanded_columns = _get_expanded_columns(columns, True, set(columns), **kwargs)
+
+        assert len(expanded_columns) == 3
+        assert len(set(expanded_columns) & set(columns)) == 3
+
+
+class TestGetThreads(unittest.TestCase):
+    def test__get_threads(self):
+        threaded, threads = _get_threads(None, None, None)
+        assert threaded
+        assert threads == 1
+
+        threaded, threads = _get_threads(None, 2, 3)
+        assert threaded
+        assert threads == 1
+
+        threaded, threads = _get_threads("serial", None, None)
+        assert not threaded
+        assert threads == 1
+
+        with self.assertRaises(AssertionError):
+            _get_threads("serial", 1, 2)
+
+        threaded, threads = _get_threads("4", None, None)
+        assert threaded
+        assert threads == 4
+
+        with self.assertRaises(ValueError) as value_error:
+            _get_threads("auto", None, None)
+        assert str(value_error.exception) == "invalid literal for int() with base 10: 'auto'"
+
+        threaded, threads = _get_threads(5, None, None)
+        assert threaded
+        assert threads == 5
+
+        threaded, threads = _get_threads(6, 7, 8)
+        assert threaded
+        assert threads == 6
+
+        with self.assertRaises(ValueError) as value_error:
+            _get_threads(0, None, None)
+        assert str(value_error.exception) == "Error: threads must be >= 1"
+
+        with self.assertRaises(ValueError) as value_error:
+            _get_threads(-1, None, None)
+        assert str(value_error.exception) == "Error: threads must be >= 1"
diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py
index ed1baecf1..4d0402040 100644
--- a/tests/test_postgresql.py
+++ b/tests/test_postgresql.py
@@ -1,11 +1,12 @@
 import unittest
-
+from copy import deepcopy
 from urllib.parse import quote
-from data_diff.queries.api import table, commit
-from data_diff import TableSegment, HashDiffer
+
+from data_diff import TableSegment, HashDiffer, Database
+from data_diff import connect_to_table
 from data_diff import databases as db
+from data_diff.queries.api import table, commit
 from tests.common import get_conn, random_table_suffix, connect
-from data_diff import connect_to_table
 
 
 class TestUUID(unittest.TestCase):
@@ -118,38 +119,40 @@ def test_100_fields(self):
 
 
 class TestSpecialCharacterPassword(unittest.TestCase):
+    username: str = "test"
+    password: str = "passw!!!@rd"
+
     def setUp(self) -> None:
-        self.connection = get_conn(db.PostgreSQL)
+        self.connection: Database = get_conn(db.PostgreSQL)
+        self.table_name = f"table{random_table_suffix()}"
 
-        table_suffix = random_table_suffix()
+        # Setup user with special character '@' in password
+        self.connection.query(f"DROP USER IF EXISTS {self.username};", None)
+        self.connection.query(f"CREATE USER {self.username} WITH PASSWORD '{self.password}';", None)
 
-        self.table_name = f"table{table_suffix}"
-        self.table = table(self.table_name)
+    def tearDown(self):
+        self.connection.query(f"DROP USER IF EXISTS {self.username};", None)
+        self.connection.close()
 
     def test_special_char_password(self):
-        password = "passw!!!@rd"
-        # Setup user with special character '@' in password
-        self.connection.query("DROP USER IF EXISTS test;", None)
-        self.connection.query(f"CREATE USER test WITH PASSWORD '{password}';", None)
-
-        password_quoted = quote(password)
-        db_config = {
-            "driver": "postgresql",
-            "host": "localhost",
-            "port": 5432,
-            "dbname": "postgres",
-            "user": "test",
-            "password": password_quoted,
-        }
+        db_config = deepcopy(self.connection._args)
+        db_config.update(
+            {
+                "driver": "postgresql",
+                "dbname": db_config.pop("database"),
+                "user": self.username,
+                "password": quote(self.password),
+            }
+        )
 
         # verify pythonic connection method
-        connect_to_table(
-            db_config,
-            self.table_name,
-        )
+        connect_to_table(db_config, self.table_name)
 
         # verify connection method with URL string unquoted after it's verified
-        db_url = f"postgresql://{db_config['user']}:{db_config['password']}@{db_config['host']}:{db_config['port']}/{db_config['dbname']}"
+        db_url = (
+            f"postgresql://{db_config['user']}:{db_config['password']}@{db_config['host']}:"
+            f"{db_config.get('port', 5432)}/{db_config['dbname']}"
+        )
 
-        connection_verified = connect(db_url)
-        assert connection_verified._args.get("password") == password
+        with connect(db_url) as connection_verified:
+            assert connection_verified._args.get("password") == self.password

From 2396ed1397f4a325bbbfb9880d8b26f68366a92e Mon Sep 17 00:00:00 2001
From: Elliot Gunn <elliot.j.gunn@gmail.com>
Date: Fri, 2 Feb 2024 11:09:05 -0500
Subject: [PATCH 91/99] Minor readme edits (#855)

* edits

* style fixes by ruff

* Update README.md

Co-authored-by: Kira Furuichi <kirafuruichi2019@u.northwestern.edu>

* Update README.md

Co-authored-by: Kira Furuichi <kirafuruichi2019@u.northwestern.edu>

* kira's edit

Co-authored-by: Kira Furuichi <kirafuruichi2019@u.northwestern.edu>

---------

Co-authored-by: elliotgunn <elliotgunn@users.noreply.github.com>
Co-authored-by: Kira Furuichi <kirafuruichi2019@u.northwestern.edu>
---
 README.md | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/README.md b/README.md
index 3db79ea65..4353f00a3 100644
--- a/README.md
+++ b/README.md
@@ -16,13 +16,14 @@ A data diff is the value-level comparison between two tables—used to identify
 
 There is a lot you can do with data-diff: you can test SQL code by comparing development or staging environment data to production, or compare source and target data to identify discrepancies when moving data between databases.
 
-# Use Cases
+# data-diff OSS & Datafold Cloud
+data-diff is an open source utility for running stateless diffs as a great single player experience.
 
-### Data Migration & Replication Testing
-data-diff is a powerful tool for comparing data when you're moving it between systems. Use it to ensure data accuracy and identify discrepancies during tasks like:
-- **Migrating** to a new data warehouse (e.g., Oracle -> Snowflake)
-- **Converting SQL** to a new transformation framework (e.g., stored procedures -> dbt)
-- Continuously **replicating data** from an OLTP database to OLAP data warehouse (e.g., MySQL -> Redshift)
+
+
+Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a company-wide experience to both supercharge your data diffing CLI experience (ex: data-diff --dbt --cloud) and run diffs manually in your CI process and within the Datafold UI. This includes [column-level lineage](https://www.datafold.com/column-level-lineage) with BI tool integrations, [CI testing](https://docs.datafold.com/deployment_testing/how_it_works/), faster cross-database diffing, and diff history.
+
+# Use Cases
 
 ### Data Development Testing
 When developing SQL code, data-diff helps you validate and preview changes by comparing data between development/staging environments and production. Here's how it works:
@@ -30,6 +31,12 @@ When developing SQL code, data-diff helps you validate and preview changes by co
 2. Run the SQL code to create a new dataset
 3. Compare this dataset with its production version or other iterations
 
+### Data Migration & Replication Testing
+data-diff is a powerful tool for comparing data when you're moving it between systems. Use it to ensure data accuracy and identify discrepancies during tasks like:
+- **Migrating** to a new data warehouse (e.g., Oracle -> Snowflake)
+- **Validating SQL transformations** from legacy solutions (e.g., stored procedures) to new transformation frameworks (e.g., dbt)
+- Continuously **replicating data** from an OLTP database to OLAP data warehouse (e.g., MySQL -> Redshift)
+
 # dbt Integration
   <p align="left">
   <img alt="dbt" src="https://seeklogo.com/images/D/dbt-logo-E4B0ED72A2-seeklogo.com.png" width="10%" />
@@ -213,13 +220,6 @@ Your database not listed here?
 
 For detailed algorithm and performance insights, explore [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md), or head to our docs to [learn more about how Datafold diffs data](https://docs.datafold.com/data_diff/how-datafold-diffs-data).
 
-
-# data-diff OSS & Datafold Cloud
-
-data-diff is an open source utility for running stateless diffs as a great single player experience.
-
-Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a company-wide experience to both supercharge your data diffing CLI experience (ex: data-diff --dbt --cloud) and run diffs manually in the UI. This includes [column-level lineage](https://www.datafold.com/column-level-lineage), [CI testing](https://docs.datafold.com/deployment_testing/how_it_works/), and diff history.
-
 ## Contributors
 
 We thank everyone who contributed so far!

From d4ca0e67a9ecf0e4abd571b14f316176badfe7c4 Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 7 Feb 2024 07:17:27 +1300
Subject: [PATCH 92/99] Fix motherduck bug (#858) (#861)

* quick debug logs

* fix the override method

* remove submods

* remove prints

* remove submods

* revert change

* Refactor dynamic database clause in DuckDB.py

* draft tests

* Add validation for input path in select_table_schema method

* style fixes by ruff

* Revert "Add validation for input path in select_table_schema method"

This reverts commit c09f9cf5ab96de7b1334517eb1dd3f90b2e57d12.

* Remove unnecessary code in test_duckdb.py

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
Co-authored-by: sungchun12 <sungchun12@users.noreply.github.com>
---
 data_diff/databases/base.py   |  2 ++
 data_diff/databases/duckdb.py |  6 ++++-
 tests/test_duckdb.py          | 42 +++++++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)
 create mode 100644 tests/test_duckdb.py

diff --git a/data_diff/databases/base.py b/data_diff/databases/base.py
index 8adea0b56..56e64076d 100644
--- a/data_diff/databases/base.py
+++ b/data_diff/databases/base.py
@@ -1046,6 +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)
+
         if not rows:
             raise RuntimeError(f"{self.name}: Table '{'.'.join(path)}' does not exist, or has no columns")
 
@@ -1060,6 +1061,7 @@ def query_table_schema(self, path: DbPath) -> Dict[str, RawColumnInfo]:
             )
             for r in rows
         }
+
         assert len(d) == len(rows)
         return d
 
diff --git a/data_diff/databases/duckdb.py b/data_diff/databases/duckdb.py
index 4cdacde87..9537ce50e 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}'"
+            f"WHERE table_name = '{table}' AND table_schema = '{schema}' and table_catalog = {dynamic_database_clause}"
         )
 
     def _normalize_table_path(self, path: DbPath) -> DbPath:
diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py
new file mode 100644
index 000000000..10c3644e3
--- /dev/null
+++ b/tests/test_duckdb.py
@@ -0,0 +1,42 @@
+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)

From cac665bd63a10bb37ef7b3bce5b7e85195e8545b Mon Sep 17 00:00:00 2001
From: Sung Won Chung <sungwonchung3@gmail.com>
Date: Wed, 7 Feb 2024 08:03:18 +1300
Subject: [PATCH 93/99] Evolve dbt data diff output (#857)

* first draft

* style fixes by ruff

* past tense consistency

* working draft of new table

* style fixes by ruff

* dbt diffs work, cloud broken for now

* remove cached git repos

* efficient naming

* add type changed count

* reorder for priority on prod changes

* tabulate value diffs

* style fixes by ruff

* less horizontal space needed

* leo's feedback

* center align values

* consistent formatting

* shorter name same meaning

* row counts and diff values working

* deps impacts works now

* default val

* more readable

* add primary key used

* add model specific CI configs

* consistency

* conditional headers

* style fixes by ruff

* cleaner implementation

* more cleaning

* consistent format

* fix unchanged calc

* remove prints

* default value

* draft up tests

* a couple more tests

* new version

* passing tests

* style fixes by ruff

* util unit test

* add unit tests

* test the templates

* fix type hints

* real test no mocking

* update tests with all the new outputs

* add more validations for mock

* fix json bug

---------

Co-authored-by: Sung Won Chung <sung@datafold.com>
Co-authored-by: sungchun12 <sungchun12@users.noreply.github.com>
Co-authored-by: Dan Lawin <daniel@datafold.com>
---
 data_diff/cloud/datafold_api.py             |   8 +-
 data_diff/dbt.py                            |  77 +++++++++++----
 data_diff/diff_tables.py                    |  17 ++--
 data_diff/utils.py                          |  66 ++++++++++---
 data_diff/version.py                        |   2 +-
 pyproject.toml                              |   2 +-
 tests/dbt_artifacts/jaffle_shop.duckdb      | Bin 3158016 -> 3158016 bytes
 tests/dbt_artifacts/target/manifest.json    |   2 +-
 tests/dbt_artifacts/target/run_results.json |   2 +-
 tests/test_dbt.py                           |  99 +++++++++++++++++---
 tests/test_utils.py                         |  90 +++++++++++++++++-
 11 files changed, 304 insertions(+), 61 deletions(-)

diff --git a/data_diff/cloud/datafold_api.py b/data_diff/cloud/datafold_api.py
index 2bba52431..f6548abbf 100644
--- a/data_diff/cloud/datafold_api.py
+++ b/data_diff/cloud/datafold_api.py
@@ -144,18 +144,22 @@ class TSummaryResultSchemaStats(pydantic.BaseModel):
     exclusive_columns: Tuple[List[str], List[str]]
 
 
+class TSummaryResultDependencyDetails(pydantic.BaseModel):
+    deps: Dict[str, List[Dict]]
+
+
 class TCloudApiDataDiffSummaryResult(pydantic.BaseModel):
     status: str
     pks: Optional[TSummaryResultPrimaryKeyStats]
     values: Optional[TSummaryResultValueStats]
     schema_: Optional[TSummaryResultSchemaStats]
-    dependencies: Optional[Dict[str, Any]]
+    deps: Optional[TSummaryResultDependencyDetails]
 
     @classmethod
     def from_orm(cls, obj: Any) -> Self:
         pks = TSummaryResultPrimaryKeyStats(**obj["pks"]) if "pks" in obj else None
         values = TSummaryResultValueStats(**obj["values"]) if "values" in obj else None
-        deps = obj["deps"] if "deps" in obj else None
+        deps = TSummaryResultDependencyDetails(**obj["dependencies"]) if "dependencies" in obj else None
         schema = TSummaryResultSchemaStats(**obj["schema"]) if "schema" in obj else None
         return cls(
             status=obj["status"],
diff --git a/data_diff/dbt.py b/data_diff/dbt.py
index 2da076e96..6e961a219 100644
--- a/data_diff/dbt.py
+++ b/data_diff/dbt.py
@@ -306,12 +306,23 @@ def _local_diff(
         k for k, v in table2_columns.items() if k in table1_columns and v.data_type != table1_columns[k].data_type
     }
 
-    if columns_added:
-        diff_output_str += columns_added_template(columns_added)
+    diff_output_str += f"Primary Keys: {diff_vars.primary_keys} \n"
+
+    if diff_vars.where_filter:
+        diff_output_str += f"Where Filter: '{str(diff_vars.where_filter)}' \n"
+
+    if diff_vars.include_columns:
+        diff_output_str += f"Included Columns: {diff_vars.include_columns} \n"
+
+    if diff_vars.exclude_columns:
+        diff_output_str += f"Excluded Columns: {diff_vars.exclude_columns} \n"
 
     if columns_removed:
         diff_output_str += columns_removed_template(columns_removed)
 
+    if columns_added:
+        diff_output_str += columns_added_template(columns_added)
+
     if columns_type_changed:
         diff_output_str += columns_type_changed_template(columns_type_changed)
         column_set = column_set.difference(columns_type_changed)
@@ -349,13 +360,14 @@ def _local_diff(
             return
 
         dataset1_columns = [
-            (name, type_, table1.database.dialect.parse_type(table1.table_path, name, type_, *other))
-            for (name, type_, *other) in table1_columns.values()
+            (info.column_name, info.data_type, table1.database.dialect.parse_type(table1.table_path, info))
+            for info in table1_columns.values()
         ]
         dataset2_columns = [
-            (name, type_, table2.database.dialect.parse_type(table2.table_path, name, type_, *other))
-            for (name, type_, *other) in table2_columns.values()
+            (info.column_name, info.data_type, table2.database.dialect.parse_type(table2.table_path, info))
+            for info in table2_columns.values()
         ]
+
         print(
             json.dumps(
                 jsonify(
@@ -455,32 +467,57 @@ def _cloud_diff(
         rows_removed_count = diff_results.pks.exclusives[0]
 
         rows_updated = diff_results.values.rows_with_differences
-        total_rows = diff_results.values.total_rows
-        rows_unchanged = int(total_rows) - int(rows_updated)
+        total_rows_table1 = diff_results.pks.total_rows[0]
+        total_rows_table2 = diff_results.pks.total_rows[1]
+        total_rows_diff = total_rows_table2 - total_rows_table1
+
+        rows_unchanged = int(total_rows_table1) - int(rows_updated) - int(rows_removed_count)
         diff_percent_list = {
-            x.column_name: str(x.match) + "%" for x in diff_results.values.columns_diff_stats if x.match != 100.0
+            x.column_name: f"{str(round(100.00 - x.match, 2))}%"
+            for x in diff_results.values.columns_diff_stats
+            if x.match != 100.0
         }
-        columns_added = diff_results.schema_.exclusive_columns[1]
-        columns_removed = diff_results.schema_.exclusive_columns[0]
+        columns_added = set(diff_results.schema_.exclusive_columns[1])
+        columns_removed = set(diff_results.schema_.exclusive_columns[0])
         column_type_changes = diff_results.schema_.column_type_differs
 
-        if columns_added:
-            diff_output_str += columns_added_template(columns_added)
+        diff_output_str += f"Primary Keys: {diff_vars.primary_keys} \n"
+        if diff_vars.where_filter:
+            diff_output_str += f"Where Filter: '{str(diff_vars.where_filter)}' \n"
+
+        if diff_vars.include_columns:
+            diff_output_str += f"Included Columns: {diff_vars.include_columns} \n"
+
+        if diff_vars.exclude_columns:
+            diff_output_str += f"Excluded Columns: {diff_vars.exclude_columns} \n"
 
         if columns_removed:
             diff_output_str += columns_removed_template(columns_removed)
 
+        if columns_added:
+            diff_output_str += columns_added_template(columns_added)
+
         if column_type_changes:
             diff_output_str += columns_type_changed_template(column_type_changes)
 
+        deps_impacts = {
+            key: len(value) + sum(len(item.get("BiHtSync", [])) for item in value) if key == "hightouch" else len(value)
+            for key, value in diff_results.deps.deps.items()
+        }
+
         if any([rows_added_count, rows_removed_count, rows_updated]):
             diff_output = dbt_diff_string_template(
-                rows_added_count,
-                rows_removed_count,
-                rows_updated,
-                str(rows_unchanged),
-                diff_percent_list,
-                "Value Match Percent:",
+                total_rows_table1=total_rows_table1,
+                total_rows_table2=total_rows_table2,
+                total_rows_diff=total_rows_diff,
+                rows_added=rows_added_count,
+                rows_removed=rows_removed_count,
+                rows_updated=rows_updated,
+                rows_unchanged=str(rows_unchanged),
+                deps_impacts=deps_impacts,
+                is_cloud=True,
+                extra_info_dict=diff_percent_list,
+                extra_info_str="Value Changed:",
             )
             diff_output_str += f"\n{diff_url}\n {diff_output} \n"
             rich.print(diff_output_str)
@@ -524,7 +561,7 @@ def _cloud_diff(
 
 
 def _diff_output_base(dev_path: str, prod_path: str) -> str:
-    return f"\n[green]{prod_path} <> {dev_path}[/] \n"
+    return f"\n[blue]{prod_path}[/] <> [green]{dev_path}[/] \n"
 
 
 def _initialize_events(dbt_user_id: Optional[str], dbt_version: Optional[str], dbt_project_id: Optional[str]) -> None:
diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 71fbf2c05..31a01a075 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -138,14 +138,19 @@ def _get_stats(self, is_dbt: bool = False) -> DiffStats:
     def get_stats_string(self, is_dbt: bool = False):
         diff_stats = self._get_stats(is_dbt)
 
+        total_rows_diff = diff_stats.table2_count - diff_stats.table1_count
+
         if is_dbt:
             string_output = dbt_diff_string_template(
-                diff_stats.diff_by_sign["+"],
-                diff_stats.diff_by_sign["-"],
-                diff_stats.diff_by_sign["!"],
-                diff_stats.unchanged,
-                diff_stats.extra_column_diffs,
-                "Values Updated:",
+                total_rows_table1=diff_stats.table1_count,
+                total_rows_table2=diff_stats.table2_count,
+                total_rows_diff=total_rows_diff,
+                rows_added=diff_stats.diff_by_sign["+"],
+                rows_removed=diff_stats.diff_by_sign["-"],
+                rows_updated=diff_stats.diff_by_sign["!"],
+                rows_unchanged=diff_stats.unchanged,
+                extra_info_dict=diff_stats.extra_column_diffs,
+                extra_info_str="[u]Values Changed[/u]",
             )
 
         else:
diff --git a/data_diff/utils.py b/data_diff/utils.py
index c4175426c..8c8e27154 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -459,19 +459,59 @@ def __repr__(self) -> str:
 
 
 def dbt_diff_string_template(
-    rows_added: str, rows_removed: str, rows_updated: str, rows_unchanged: str, extra_info_dict: Dict, extra_info_str
+    total_rows_table1: int,
+    total_rows_table2: int,
+    total_rows_diff: int,
+    rows_added: int,
+    rows_removed: int,
+    rows_updated: int,
+    rows_unchanged: int,
+    extra_info_dict: Dict,
+    extra_info_str: str,
+    is_cloud: Optional[bool] = False,
+    deps_impacts: Optional[Dict] = None,
 ) -> str:
-    string_output = f"\n{tabulate([[rows_added, rows_removed]], headers=['Rows Added', 'Rows Removed'])}"
+    # main table
+    main_rows = [
+        ["Total", total_rows_table1, "", f"{total_rows_table2} [{diff_int_dynamic_color_template(total_rows_diff)}]"],
+        ["Added", "", diff_int_dynamic_color_template(rows_added), ""],
+        ["Removed", "", diff_int_dynamic_color_template(-rows_removed), ""],
+        ["Different", "", rows_updated, ""],
+        ["Unchanged", "", rows_unchanged, ""],
+    ]
+
+    main_headers = ["rows", "PROD", "<>", "DEV"]
+    main_table = tabulate(main_rows, headers=main_headers)
+
+    # diffs table
+    diffs_rows = sorted(list(extra_info_dict.items()))
+
+    diffs_headers = ["columns", "% diff values" if is_cloud else "# diff values"]
+    diffs_table = tabulate(diffs_rows, headers=diffs_headers)
+
+    # deps impacts table
+    deps_impacts_table = ""
+    if deps_impacts:
+        deps_impacts_rows = list(deps_impacts.items())
+        deps_impacts_headers = ["deps", "# data assets"]
+        deps_impacts_table = f"\n\n{tabulate(deps_impacts_rows, headers=deps_impacts_headers)}"
+
+    # combine all tables
+    string_output = f"\n{main_table}\n\n{diffs_table}{deps_impacts_table}"
 
-    string_output += f"\n\nUpdated Rows: {rows_updated}\n"
-    string_output += f"Unchanged Rows: {rows_unchanged}\n\n"
+    return string_output
 
-    string_output += extra_info_str
 
-    for k, v in extra_info_dict.items():
-        string_output += f"\n{k}: {v}"
+def diff_int_dynamic_color_template(diff_value: int) -> str:
+    if not isinstance(diff_value, int):
+        return diff_value
 
-    return string_output
+    if diff_value > 0:
+        return f"[green]+{diff_value}[/]"
+    elif diff_value < 0:
+        return f"[red]{diff_value}[/]"
+    else:
+        return "0"
 
 
 def _jsons_equiv(a: str, b: str):
@@ -498,18 +538,18 @@ def diffs_are_equiv_jsons(diff: list, json_cols: dict):
     return match, overriden_diff_cols
 
 
-def columns_removed_template(columns_removed) -> str:
-    columns_removed_str = f"Column(s) removed: {columns_removed}\n"
+def columns_removed_template(columns_removed: set) -> str:
+    columns_removed_str = f"[red]Columns removed [-{len(columns_removed)}]:[/] [blue]{columns_removed}[/]\n"
     return columns_removed_str
 
 
-def columns_added_template(columns_added) -> str:
-    columns_added_str = f"Column(s) added: {columns_added}\n"
+def columns_added_template(columns_added: set) -> str:
+    columns_added_str = f"[green]Columns added [+{len(columns_added)}]: {columns_added}[/]\n"
     return columns_added_str
 
 
 def columns_type_changed_template(columns_type_changed) -> str:
-    columns_type_changed_str = f"Type change: {columns_type_changed}\n"
+    columns_type_changed_str = f"Type changed [{len(columns_type_changed)}]: [green]{columns_type_changed}[/]\n"
     return columns_type_changed_str
 
 
diff --git a/data_diff/version.py b/data_diff/version.py
index 1f4c4d43b..ae6db5f17 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.10.1"
+__version__ = "0.11.0"
diff --git a/pyproject.toml b/pyproject.toml
index 340cc1998..13663d8d1 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.10.1"
+version = "0.11.0"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"
diff --git a/tests/dbt_artifacts/jaffle_shop.duckdb b/tests/dbt_artifacts/jaffle_shop.duckdb
index b0899b5f32b35b8e12da6cb2236d98a05a7b6b6a..c36b00f56e30cb0b6b780afcc982072f8140b741 100644
GIT binary patch
diff --git a/tests/dbt_artifacts/target/manifest.json b/tests/dbt_artifacts/target/manifest.json
index f46aa2542..46254a58a 100644
--- a/tests/dbt_artifacts/target/manifest.json
+++ b/tests/dbt_artifacts/target/manifest.json
@@ -1 +1 @@
-{"metadata": {"dbt_schema_version": "https://schemas.getdbt.com/dbt/manifest/v8.json", "dbt_version": "1.4.5", "generated_at": "2023-03-28T17:53:00.231489Z", "invocation_id": "289d7789-15b8-44be-a1f6-828f34858212", "env": {}, "project_id": "06e5b98c2db46f8a72cc4f66410e9b3b", "user_id": "1974995a-a39c-4b24-bacf-adfe12e92602", "send_anonymous_usage_stats": true, "adapter_type": "duckdb"}, "nodes": {"model.jaffle_shop.customers": {"database": "jaffle_shop", "schema": "dev", "name": "customers", "resource_type": "model", "package_name": "jaffle_shop", "path": "customers.sql", "original_file_path": "models/customers.sql", "unique_id": "model.jaffle_shop.customers", "fqn": ["jaffle_shop", "customers"], "alias": "customers", "checksum": {"name": "sha256", "checksum": "455b90a31f418ae776213ad9932c7cb72d19a5269a8c722bd9f4e44957313ce8"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "table", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "post-hook": [], "pre-hook": []}, "tags": [], "description": "This table has basic information about a customer, as well as some derived facts based on a customer's orders", "columns": {"customer_id": {"name": "customer_id", "description": "This is a unique identifier for a customer", "meta": {}, "data_type": null, "quote": null, "tags": ["primary-key"]}, "first_name": {"name": "first_name", "description": "Customer's first name. PII.", "meta": {}, "data_type": null, "quote": null, "tags": []}, "last_name": {"name": "last_name", "description": "Customer's last name. PII.", "meta": {}, "data_type": null, "quote": null, "tags": []}, "first_order": {"name": "first_order", "description": "Date (UTC) of a customer's first order", "meta": {}, "data_type": null, "quote": null, "tags": []}, "most_recent_order": {"name": "most_recent_order", "description": "Date (UTC) of a customer's most recent order", "meta": {}, "data_type": null, "quote": null, "tags": []}, "number_of_orders": {"name": "number_of_orders", "description": "Count of the number of orders a customer has placed", "meta": {}, "data_type": null, "quote": null, "tags": []}, "total_order_amount": {"name": "total_order_amount", "description": "Total value (AUD) of a customer's orders", "meta": {}, "data_type": null, "quote": null, "tags": []}}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": "jaffle_shop://models/schema.yml", "build_path": "target/run/jaffle_shop/models/customers.sql", "deferred": false, "unrendered_config": {"materialized": "table"}, "created_at": 1680025829.8450181, "relation_name": "\"jaffle_shop\".\"dev\".\"customers\"", "raw_code": "with customers as (\n\n    select * from {{ ref('stg_customers') }}\n\n),\n\norders as (\n\n    select * from {{ ref('stg_orders') }}\n\n),\n\npayments as (\n\n    select * from {{ ref('stg_payments') }}\n\n),\n\ncustomer_orders as (\n\n        select\n        customer_id,\n\n        min(order_date) as first_order,\n        max(order_date) as most_recent_order,\n        count(order_id) as number_of_orders\n    from orders\n\n    group by customer_id\n\n),\n\ncustomer_payments as (\n\n    select\n        orders.customer_id,\n        sum(amount) as total_amount\n\n    from payments\n\n    left join orders on\n         payments.order_id = orders.order_id\n\n    group by orders.customer_id\n\n),\n\nfinal as (\n\n    select\n        customers.customer_id,\n        customers.first_name,\n        customers.last_name,\n        customer_orders.first_order,\n        customer_orders.most_recent_order,\n        customer_orders.number_of_orders,\n        customer_payments.total_amount as customer_lifetime_value\n\n    from customers\n\n    left join customer_orders\n        on customers.customer_id = customer_orders.customer_id\n\n    left join customer_payments\n        on  customers.customer_id = customer_payments.customer_id\n\n)\n\nselect * from final", "language": "sql", "refs": [["stg_customers"], ["stg_orders"], ["stg_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["model.jaffle_shop.stg_customers", "model.jaffle_shop.stg_orders", "model.jaffle_shop.stg_payments"]}, "compiled_path": "target/compiled/jaffle_shop/models/customers.sql", "compiled": true, "compiled_code": "with customers as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_customers\"\n\n),\n\norders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\ncustomer_orders as (\n\n        select\n        customer_id,\n\n        min(order_date) as first_order,\n        max(order_date) as most_recent_order,\n        count(order_id) as number_of_orders\n    from orders\n\n    group by customer_id\n\n),\n\ncustomer_payments as (\n\n    select\n        orders.customer_id,\n        sum(amount) as total_amount\n\n    from payments\n\n    left join orders on\n         payments.order_id = orders.order_id\n\n    group by orders.customer_id\n\n),\n\nfinal as (\n\n    select\n        customers.customer_id,\n        customers.first_name,\n        customers.last_name,\n        customer_orders.first_order,\n        customer_orders.most_recent_order,\n        customer_orders.number_of_orders,\n        customer_payments.total_amount as customer_lifetime_value\n\n    from customers\n\n    left join customer_orders\n        on customers.customer_id = customer_orders.customer_id\n\n    left join customer_payments\n        on  customers.customer_id = customer_payments.customer_id\n\n)\n\nselect * from final", "extra_ctes_injected": true, "extra_ctes": []}, "model.jaffle_shop.orders": {"database": "jaffle_shop", "schema": "dev", "name": "orders", "resource_type": "model", "package_name": "jaffle_shop", "path": "orders.sql", "original_file_path": "models/orders.sql", "unique_id": "model.jaffle_shop.orders", "fqn": ["jaffle_shop", "orders"], "alias": "orders", "checksum": {"name": "sha256", "checksum": "c99b996bdc622502e5d0062779f76f74331f88824cffbd36d14cc6075c394d9a"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "table", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "post-hook": [], "pre-hook": []}, "tags": [], "description": "This table has basic information about orders, as well as some derived facts based on payments", "columns": {"order_id": {"name": "order_id", "description": "This is a unique identifier for an order", "meta": {}, "data_type": null, "quote": null, "tags": ["primary-key"]}, "customer_id": {"name": "customer_id", "description": "Foreign key to the customers table", "meta": {}, "data_type": null, "quote": null, "tags": []}, "order_date": {"name": "order_date", "description": "Date (UTC) that the order was placed", "meta": {}, "data_type": null, "quote": null, "tags": []}, "status": {"name": "status", "description": "Orders can be one of the following statuses:\n\n| status         | description                                                                                                            |\n|----------------|------------------------------------------------------------------------------------------------------------------------|\n| placed         | The order has been placed but has not yet left the warehouse                                                           |\n| shipped        | The order has ben shipped to the customer and is currently in transit                                                  |\n| completed      | The order has been received by the customer                                                                            |\n| return_pending | The customer has indicated that they would like to return the order, but it has not yet been received at the warehouse |\n| returned       | The order has been returned by the customer and received at the warehouse                                              |", "meta": {}, "data_type": null, "quote": null, "tags": []}, "amount": {"name": "amount", "description": "Total amount (AUD) of the order", "meta": {}, "data_type": null, "quote": null, "tags": []}, "credit_card_amount": {"name": "credit_card_amount", "description": "Amount of the order (AUD) paid for by credit card", "meta": {}, "data_type": null, "quote": null, "tags": []}, "coupon_amount": {"name": "coupon_amount", "description": "Amount of the order (AUD) paid for by coupon", "meta": {}, "data_type": null, "quote": null, "tags": []}, "bank_transfer_amount": {"name": "bank_transfer_amount", "description": "Amount of the order (AUD) paid for by bank transfer", "meta": {}, "data_type": null, "quote": null, "tags": []}, "gift_card_amount": {"name": "gift_card_amount", "description": "Amount of the order (AUD) paid for by gift card", "meta": {}, "data_type": null, "quote": null, "tags": []}}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": "jaffle_shop://models/schema.yml", "build_path": "target/run/jaffle_shop/models/orders.sql", "deferred": false, "unrendered_config": {"materialized": "table"}, "created_at": 1680025829.846783, "relation_name": "\"jaffle_shop\".\"dev\".\"orders\"", "raw_code": "{% set payment_methods = ['credit_card', 'coupon', 'bank_transfer', 'gift_card'] %}\n\nwith orders as (\n\n    select * from {{ ref('stg_orders') }}\n\n),\n\npayments as (\n\n    select * from {{ ref('stg_payments') }}\n\n),\n\norder_payments as (\n\n    select\n        order_id,\n\n        {% for payment_method in payment_methods -%}\n        sum(case when payment_method = '{{ payment_method }}' then amount else 0 end) as {{ payment_method }}_amount,\n        {% endfor -%}\n\n        sum(amount) as total_amount\n\n    from payments\n\n    group by order_id\n\n),\n\nfinal as (\n\n    select\n        orders.order_id,\n        orders.customer_id,\n        orders.order_date,\n        orders.status,\n\n        {% for payment_method in payment_methods -%}\n\n        order_payments.{{ payment_method }}_amount,\n\n        {% endfor -%}\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n)\n\nselect * from final\nLIMIT 90", "language": "sql", "refs": [["stg_orders"], ["stg_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["model.jaffle_shop.stg_orders", "model.jaffle_shop.stg_payments"]}, "compiled_path": "target/compiled/jaffle_shop/models/orders.sql", "compiled": true, "compiled_code": "\n\nwith orders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\norder_payments as (\n\n    select\n        order_id,\n\n        sum(case when payment_method = 'credit_card' then amount else 0 end) as credit_card_amount,\n        sum(case when payment_method = 'coupon' then amount else 0 end) as coupon_amount,\n        sum(case when payment_method = 'bank_transfer' then amount else 0 end) as bank_transfer_amount,\n        sum(case when payment_method = 'gift_card' then amount else 0 end) as gift_card_amount,\n        sum(amount) as total_amount\n\n    from payments\n\n    group by order_id\n\n),\n\nfinal as (\n\n    select\n        orders.order_id,\n        orders.customer_id,\n        orders.order_date,\n        orders.status,\n\n        order_payments.credit_card_amount,\n\n        order_payments.coupon_amount,\n\n        order_payments.bank_transfer_amount,\n\n        order_payments.gift_card_amount,\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n)\n\nselect * from final\nLIMIT 90", "extra_ctes_injected": true, "extra_ctes": []}, "model.jaffle_shop.stg_customers": {"database": "jaffle_shop", "schema": "dev", "name": "stg_customers", "resource_type": "model", "package_name": "jaffle_shop", "path": "staging/stg_customers.sql", "original_file_path": "models/staging/stg_customers.sql", "unique_id": "model.jaffle_shop.stg_customers", "fqn": ["jaffle_shop", "staging", "stg_customers"], "alias": "stg_customers", "checksum": {"name": "sha256", "checksum": "6f18a29204dad1de6dbb0c288144c4990742e0a1e065c3b2a67b5f98334c22ba"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {"customer_id": {"name": "customer_id", "description": "", "meta": {}, "data_type": null, "quote": null, "tags": ["primary-key"]}}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": "jaffle_shop://models/staging/schema.yml", "build_path": "target/run/jaffle_shop/models/staging/stg_customers.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1680025829.869041, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_customers\"", "raw_code": "with source as (\n\n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_customers') }}\n\n),\n\nrenamed as (\n\n    select\n        id as customer_id,\n        first_name,\n        last_name\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [["raw_customers"]], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.jaffle_shop.raw_customers"]}, "compiled_path": "target/compiled/jaffle_shop/models/staging/stg_customers.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_customers\"\n\n),\n\nrenamed as (\n\n    select\n        id as customer_id,\n        first_name,\n        last_name\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": []}, "model.jaffle_shop.stg_payments": {"database": "jaffle_shop", "schema": "dev", "name": "stg_payments", "resource_type": "model", "package_name": "jaffle_shop", "path": "staging/stg_payments.sql", "original_file_path": "models/staging/stg_payments.sql", "unique_id": "model.jaffle_shop.stg_payments", "fqn": ["jaffle_shop", "staging", "stg_payments"], "alias": "stg_payments", "checksum": {"name": "sha256", "checksum": "ec8712986e99fdea30feaba2144bb9eca2bb6dc862880cbb6e21831857595fe0"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {"payment_id": {"name": "payment_id", "description": "", "meta": {}, "data_type": null, "quote": null, "tags": ["primary-key"]}, "payment_method": {"name": "payment_method", "description": "", "meta": {}, "data_type": null, "quote": null, "tags": []}}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": "jaffle_shop://models/staging/schema.yml", "build_path": "target/run/jaffle_shop/models/staging/stg_payments.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1680025829.870419, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_payments\"", "raw_code": "with source as (\n    \n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_payments') }}\n\n),\n\nrenamed as (\n\n    select\n        id as payment_id,\n        order_id,\n        payment_method,\n\n        -- `amount` is currently stored in cents, so we convert it to dollars\n        amount / 100 as amount,\n        amount as amount_cents\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [["raw_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.jaffle_shop.raw_payments"]}, "compiled_path": "target/compiled/jaffle_shop/models/staging/stg_payments.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_payments\"\n\n),\n\nrenamed as (\n\n    select\n        id as payment_id,\n        order_id,\n        payment_method,\n\n        -- `amount` is currently stored in cents, so we convert it to dollars\n        amount / 100 as amount,\n        amount as amount_cents\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": []}, "model.jaffle_shop.stg_orders": {"database": "jaffle_shop", "schema": "dev", "name": "stg_orders", "resource_type": "model", "package_name": "jaffle_shop", "path": "staging/stg_orders.sql", "original_file_path": "models/staging/stg_orders.sql", "unique_id": "model.jaffle_shop.stg_orders", "fqn": ["jaffle_shop", "staging", "stg_orders"], "alias": "stg_orders", "checksum": {"name": "sha256", "checksum": "afffa9cbc57e5fd2cf5898ebf571d444a62c9d6d7929d8133d30567fb9a2ce97"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {"order_id": {"name": "order_id", "description": "", "meta": {}, "data_type": null, "quote": null, "tags": ["primary-key"]}, "status": {"name": "status", "description": "", "meta": {}, "data_type": null, "quote": null, "tags": []}}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": "jaffle_shop://models/staging/schema.yml", "build_path": "target/run/jaffle_shop/models/staging/stg_orders.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1680025829.869803, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_orders\"", "raw_code": "with source as (\n\n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_orders') }}\n\n),\n\nrenamed as (\n\n    select\n        id as order_id,\n        user_id as customer_id,\n        order_date,\n        status\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [["raw_orders"]], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.jaffle_shop.raw_orders"]}, "compiled_path": "target/compiled/jaffle_shop/models/staging/stg_orders.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_orders\"\n\n),\n\nrenamed as (\n\n    select\n        id as order_id,\n        user_id as customer_id,\n        order_date,\n        status\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": []}, "seed.jaffle_shop.raw_customers": {"database": "jaffle_shop", "schema": "dev", "name": "raw_customers", "resource_type": "seed", "package_name": "jaffle_shop", "path": "raw_customers.csv", "original_file_path": "seeds/raw_customers.csv", "unique_id": "seed.jaffle_shop.raw_customers", "fqn": ["jaffle_shop", "raw_customers"], "alias": "raw_customers", "checksum": {"name": "sha256", "checksum": "24579b4b26098d43265376f3c50be8b10faf8e8fd95f5508074f10f76a12671d"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "quote_columns": null, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.8330948, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_customers\"", "raw_code": "", "root_path": "/Users/dan/repos/jaffle_shop", "depends_on": {"macros": []}}, "seed.jaffle_shop.raw_orders": {"database": "jaffle_shop", "schema": "dev", "name": "raw_orders", "resource_type": "seed", "package_name": "jaffle_shop", "path": "raw_orders.csv", "original_file_path": "seeds/raw_orders.csv", "unique_id": "seed.jaffle_shop.raw_orders", "fqn": ["jaffle_shop", "raw_orders"], "alias": "raw_orders", "checksum": {"name": "sha256", "checksum": "ee6c68d1639ec2b23a4495ec12475e09b8ed4b61e23ab0411ea7ec76648356f7"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "quote_columns": null, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.834146, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_orders\"", "raw_code": "", "root_path": "/Users/dan/repos/jaffle_shop", "depends_on": {"macros": []}}, "seed.jaffle_shop.raw_payments": {"database": "jaffle_shop", "schema": "dev", "name": "raw_payments", "resource_type": "seed", "package_name": "jaffle_shop", "path": "raw_payments.csv", "original_file_path": "seeds/raw_payments.csv", "unique_id": "seed.jaffle_shop.raw_payments", "fqn": ["jaffle_shop", "raw_payments"], "alias": "raw_payments", "checksum": {"name": "sha256", "checksum": "03fd407f3135f84456431a923f22fc185a2154079e210c20b690e3ab11687d11"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "quote_columns": null, "post-hook": [], "pre-hook": []}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.8351219, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_payments\"", "raw_code": "", "root_path": "/Users/dan/repos/jaffle_shop", "depends_on": {"macros": []}}, "test.jaffle_shop.unique_customers_customer_id.c5af1ff4b1": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_customers_customer_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "unique_customers_customer_id.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.unique_customers_customer_id.c5af1ff4b1", "fqn": ["jaffle_shop", "unique_customers_customer_id"], "alias": "unique_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.850326, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["customers"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.jaffle_shop.customers"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.customers"}, "test.jaffle_shop.not_null_customers_customer_id.5c9bf9911d": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_customers_customer_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_customers_customer_id.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_customers_customer_id.5c9bf9911d", "fqn": ["jaffle_shop", "not_null_customers_customer_id"], "alias": "not_null_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.851261, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["customers"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.customers"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.customers"}, "test.jaffle_shop.unique_orders_order_id.fed79b3a6e": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_orders_order_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "unique_orders_order_id.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.unique_orders_order_id.fed79b3a6e", "fqn": ["jaffle_shop", "unique_orders_order_id"], "alias": "unique_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.852126, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "order_id", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_order_id.cf6c17daed": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_order_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_order_id.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_order_id.cf6c17daed", "fqn": ["jaffle_shop", "not_null_orders_order_id"], "alias": "not_null_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.852982, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "order_id", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_customer_id.c5f02694af": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_customer_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_customer_id.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_customer_id.c5f02694af", "fqn": ["jaffle_shop", "not_null_orders_customer_id"], "alias": "not_null_orders_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.8539362, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.orders"}, "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2": {"test_metadata": {"name": "relationships", "kwargs": {"to": "ref('customers')", "field": "customer_id", "column_name": "customer_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "relationships_orders_customer_id__customer_id__ref_customers_", "resource_type": "test", "package_name": "jaffle_shop", "path": "relationships_orders_customer_id__customer_id__ref_customers_.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2", "fqn": ["jaffle_shop", "relationships_orders_customer_id__customer_id__ref_customers_"], "alias": "relationships_orders_customer_id__customer_id__ref_customers_", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.854784, "relation_name": null, "raw_code": "{{ test_relationships(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["customers"], ["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_relationships", "macro.dbt.get_where_subquery"], "nodes": ["model.jaffle_shop.customers", "model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.orders"}, "test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["placed", "shipped", "completed", "return_pending", "returned"], "column_name": "status", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_orders_status__placed__shipped__completed__return_pending__returned", "resource_type": "test", "package_name": "jaffle_shop", "path": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3", "fqn": ["jaffle_shop", "accepted_values_orders_status__placed__shipped__completed__return_pending__returned"], "alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758"}, "created_at": 1680025829.85997, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758\") }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "status", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_amount.106140f9fd": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_amount", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_amount.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_amount.106140f9fd", "fqn": ["jaffle_shop", "not_null_orders_amount"], "alias": "not_null_orders_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.864409, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "amount", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "credit_card_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_credit_card_amount", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_credit_card_amount.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59", "fqn": ["jaffle_shop", "not_null_orders_credit_card_amount"], "alias": "not_null_orders_credit_card_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.865262, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "credit_card_amount", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "coupon_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_coupon_amount", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_coupon_amount.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625", "fqn": ["jaffle_shop", "not_null_orders_coupon_amount"], "alias": "not_null_orders_coupon_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.866215, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "coupon_amount", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "bank_transfer_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_bank_transfer_amount", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_bank_transfer_amount.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49", "fqn": ["jaffle_shop", "not_null_orders_bank_transfer_amount"], "alias": "not_null_orders_bank_transfer_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.867062, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "bank_transfer_amount", "file_key_name": "models.orders"}, "test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "gift_card_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_gift_card_amount", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_orders_gift_card_amount.sql", "original_file_path": "models/schema.yml", "unique_id": "test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a", "fqn": ["jaffle_shop", "not_null_orders_gift_card_amount"], "alias": "not_null_orders_gift_card_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.8679218, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.orders"]}, "compiled_path": null, "column_name": "gift_card_amount", "file_key_name": "models.orders"}, "test.jaffle_shop.unique_stg_customers_customer_id.c7614daada": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('stg_customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_customers_customer_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "unique_stg_customers_customer_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.unique_stg_customers_customer_id.c7614daada", "fqn": ["jaffle_shop", "staging", "unique_stg_customers_customer_id"], "alias": "unique_stg_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.870772, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_customers"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.jaffle_shop.stg_customers"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.stg_customers"}, "test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('stg_customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_customers_customer_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_stg_customers_customer_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa", "fqn": ["jaffle_shop", "staging", "not_null_stg_customers_customer_id"], "alias": "not_null_stg_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.871656, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_customers"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.stg_customers"]}, "compiled_path": null, "column_name": "customer_id", "file_key_name": "models.stg_customers"}, "test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_orders_order_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "unique_stg_orders_order_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a", "fqn": ["jaffle_shop", "staging", "unique_stg_orders_order_id"], "alias": "unique_stg_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.87264, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.jaffle_shop.stg_orders"]}, "compiled_path": null, "column_name": "order_id", "file_key_name": "models.stg_orders"}, "test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_orders_order_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_stg_orders_order_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64", "fqn": ["jaffle_shop", "staging", "not_null_stg_orders_order_id"], "alias": "not_null_stg_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.873489, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.stg_orders"]}, "compiled_path": null, "column_name": "order_id", "file_key_name": "models.stg_orders"}, "test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["placed", "shipped", "completed", "return_pending", "returned"], "column_name": "status", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned", "resource_type": "test", "package_name": "jaffle_shop", "path": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad", "fqn": ["jaffle_shop", "staging", "accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned"], "alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58"}, "created_at": 1680025829.874337, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58\") }}", "language": "sql", "refs": [["stg_orders"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.jaffle_shop.stg_orders"]}, "compiled_path": null, "column_name": "status", "file_key_name": "models.stg_orders"}, "test.jaffle_shop.unique_stg_payments_payment_id.3744510712": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "payment_id", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_payments_payment_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "unique_stg_payments_payment_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.unique_stg_payments_payment_id.3744510712", "fqn": ["jaffle_shop", "staging", "unique_stg_payments_payment_id"], "alias": "unique_stg_payments_payment_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.877381, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.jaffle_shop.stg_payments"]}, "compiled_path": null, "column_name": "payment_id", "file_key_name": "models.stg_payments"}, "test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "payment_id", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_payments_payment_id", "resource_type": "test", "package_name": "jaffle_shop", "path": "not_null_stg_payments_payment_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075", "fqn": ["jaffle_shop", "staging", "not_null_stg_payments_payment_id"], "alias": "not_null_stg_payments_payment_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": ["primary-key"], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1680025829.8782341, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [["stg_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.jaffle_shop.stg_payments"]}, "compiled_path": null, "column_name": "payment_id", "file_key_name": "models.stg_payments"}, "test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["credit_card", "coupon", "bank_transfer", "gift_card"], "column_name": "payment_method", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card", "resource_type": "test", "package_name": "jaffle_shop", "path": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278", "fqn": ["jaffle_shop", "staging", "accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card"], "alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "materialized": "test", "severity": "ERROR", "store_failures": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef"}, "created_at": 1680025829.87921, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef\") }}", "language": "sql", "refs": [["stg_payments"]], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.jaffle_shop.stg_payments"]}, "compiled_path": null, "column_name": "payment_method", "file_key_name": "models.stg_payments"}}, "sources": {}, "macros": {"macro.dbt_duckdb.duckdb__get_binding_char": {"name": "duckdb__get_binding_char", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_binding_char", "macro_sql": "{% macro duckdb__get_binding_char() %}\n  {{ return('?') }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.528875, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_batch_size": {"name": "duckdb__get_batch_size", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_batch_size", "macro_sql": "{% macro duckdb__get_batch_size() %}\n  {{ return(10000) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.529001, "supported_languages": null}, "macro.dbt_duckdb.duckdb__load_csv_rows": {"name": "duckdb__load_csv_rows", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__load_csv_rows", "macro_sql": "{% macro duckdb__load_csv_rows(model, agate_table) %}\n    {% set batch_size = get_batch_size() %}\n    {% set agate_table = adapter.convert_datetimes_to_strs(agate_table) %}\n    {% set cols_sql = get_seed_column_quoted_csv(model, agate_table.column_names) %}\n    {% set bindings = [] %}\n\n    {% set statements = [] %}\n\n    {% for chunk in agate_table.rows | batch(batch_size) %}\n        {% set bindings = [] %}\n\n        {% for row in chunk %}\n            {% do bindings.extend(row) %}\n        {% endfor %}\n\n        {% set sql %}\n            insert into {{ this.render() }} ({{ cols_sql }}) values\n            {% for row in chunk -%}\n                ({%- for column in agate_table.column_names -%}\n                    {{ get_binding_char() }}\n                    {%- if not loop.last%},{%- endif %}\n                {%- endfor -%})\n                {%- if not loop.last%},{%- endif %}\n            {%- endfor %}\n        {% endset %}\n\n        {% do adapter.add_query(sql, bindings=bindings, abridge_sql_log=True) %}\n\n        {% if loop.index0 == 0 %}\n            {% do statements.append(sql) %}\n        {% endif %}\n    {% endfor %}\n\n    {# Return SQL so we can render it out into the compiled files #}\n    {{ return(statements[0]) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_batch_size", "macro.dbt.get_seed_column_quoted_csv", "macro.dbt.get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5302458, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_merge_sql": {"name": "duckdb__snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/snapshot_merge.sql", "original_file_path": "macros/snapshot_merge.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_merge_sql", "macro_sql": "{% macro duckdb__snapshot_merge_sql(target, source, insert_cols) -%}\n    {%- set insert_cols_csv = insert_cols | join(', ') -%}\n\n    {% set insert_sql %}\n    insert into {{ target }} ({{ insert_cols_csv }})\n    select {% for column in insert_cols -%}\n        DBT_INTERNAL_SOURCE.{{ column }} {%- if not loop.last %}, {%- endif %}\n    {%- endfor %}\n    from {{ source }} as DBT_INTERNAL_SOURCE\n    where DBT_INTERNAL_SOURCE.dbt_change_type = 'insert';\n    {% endset %}\n\n    {% do adapter.add_query(insert_sql, auto_begin=False) %}\n\n    update {{ target }}\n    set dbt_valid_to = DBT_INTERNAL_SOURCE.dbt_valid_to\n    from {{ source }} as DBT_INTERNAL_SOURCE\n    where DBT_INTERNAL_SOURCE.dbt_scd_id = {{ target.identifier }}.dbt_scd_id\n      and DBT_INTERNAL_SOURCE.dbt_change_type = 'update'\n      and {{ target.identifier }}.dbt_valid_to is null;\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5310872, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_catalog": {"name": "duckdb__get_catalog", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/catalog.sql", "original_file_path": "macros/catalog.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_catalog", "macro_sql": "{% macro duckdb__get_catalog(information_schema, schemas) -%}\n  {%- call statement('catalog', fetch_result=True) -%}\n    select\n        '{{ database }}' as table_database,\n        t.table_schema,\n        t.table_name,\n        t.table_type,\n        '' as table_comment,\n        c.column_name,\n        c.ordinal_position as column_index,\n        c.data_type column_type,\n        '' as column_comment,\n        '' as table_owner\n    FROM information_schema.tables t JOIN information_schema.columns c ON t.table_schema = c.table_schema AND t.table_name = c.table_name\n    WHERE (\n        {%- for schema in schemas -%}\n          upper(t.table_schema) = upper('{{ schema }}'){%- if not loop.last %} or {% endif -%}\n        {%- endfor -%}\n    )\n    AND t.table_type IN ('BASE TABLE', 'VIEW')\n    ORDER BY\n        t.table_schema,\n        t.table_name,\n        c.ordinal_position\n  {%- endcall -%}\n  {{ return(load_result('catalog').table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.531669, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_schema": {"name": "duckdb__create_schema", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_schema", "macro_sql": "{% macro duckdb__create_schema(relation) -%}\n  {%- call statement('create_schema') -%}\n    create schema if not exists {{ relation.without_identifier().include(database=adapter.use_database()) }}\n  {%- endcall -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.541016, "supported_languages": null}, "macro.dbt_duckdb.duckdb__drop_schema": {"name": "duckdb__drop_schema", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__drop_schema", "macro_sql": "{% macro duckdb__drop_schema(relation) -%}\n  {%- call statement('drop_schema') -%}\n    drop schema if exists {{ relation.without_identifier().include(database=adapter.use_database()) }} cascade\n  {%- endcall -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.541246, "supported_languages": null}, "macro.dbt_duckdb.duckdb__list_schemas": {"name": "duckdb__list_schemas", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__list_schemas", "macro_sql": "{% macro duckdb__list_schemas(database) -%}\n  {% set sql %}\n    select schema_name\n    from information_schema.schemata\n  {% endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.541417, "supported_languages": null}, "macro.dbt_duckdb.duckdb__check_schema_exists": {"name": "duckdb__check_schema_exists", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__check_schema_exists", "macro_sql": "{% macro duckdb__check_schema_exists(information_schema, schema) -%}\n  {% set sql -%}\n        select count(*)\n        from information_schema.schemata\n        where schema_name='{{ schema }}'\n  {%- endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.541627, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_table_as": {"name": "duckdb__create_table_as", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_table_as", "macro_sql": "{% macro duckdb__create_table_as(temporary, relation, compiled_code, language='sql') -%}\n  {%- if language == 'sql' -%}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {{ sql_header if sql_header is not none }}\n\n    create {% if temporary: -%}temporary{%- endif %} table\n      {{ relation.include(database=(not temporary and adapter.use_database()), schema=(not temporary)) }}\n    as (\n      {{ compiled_code }}\n    );\n  {%- elif language == 'python' -%}\n    {{ py_write_table(temporary=temporary, relation=relation, compiled_code=compiled_code) }}\n  {%- else -%}\n      {% do exceptions.raise_compiler_error(\"duckdb__create_table_as macro didn't get supported language, it got %s\" % language) %}\n  {%- endif -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.py_write_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.542319, "supported_languages": null}, "macro.dbt_duckdb.py_write_table": {"name": "py_write_table", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.py_write_table", "macro_sql": "{% macro py_write_table(temporary, relation, compiled_code) -%}\n{{ compiled_code }}\n\ndef materialize(df, con):\n    try:\n        import pyarrow\n    except ImportError:\n        pass\n    finally:\n        if isinstance(df, pyarrow.Table):\n            # https://github.com/duckdb/duckdb/issues/6584\n            import pyarrow.dataset\n    con.execute('create table {{ relation.include(database=adapter.use_database()) }} as select * from df')\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.542516, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_view_as": {"name": "duckdb__create_view_as", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_view_as", "macro_sql": "{% macro duckdb__create_view_as(relation, sql) -%}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n  create view {{ relation.include(database=adapter.use_database()) }} as (\n    {{ sql }}\n  );\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.542791, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_columns_in_relation": {"name": "duckdb__get_columns_in_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_columns_in_relation", "macro_sql": "{% macro duckdb__get_columns_in_relation(relation) -%}\n  {% call statement('get_columns_in_relation', fetch_result=True) %}\n      select\n          column_name,\n          data_type,\n          character_maximum_length,\n          numeric_precision,\n          numeric_scale\n\n      from information_schema.columns\n      where table_name = '{{ relation.identifier }}'\n        {% if relation.schema %}\n        and table_schema = '{{ relation.schema }}'\n        {% endif %}\n      order by ordinal_position\n\n  {% endcall %}\n  {% set table = load_result('get_columns_in_relation').table %}\n  {{ return(sql_convert_columns_in_relation(table)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.sql_convert_columns_in_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.543176, "supported_languages": null}, "macro.dbt_duckdb.duckdb__list_relations_without_caching": {"name": "duckdb__list_relations_without_caching", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__list_relations_without_caching", "macro_sql": "{% macro duckdb__list_relations_without_caching(schema_relation) %}\n  {% call statement('list_relations_without_caching', fetch_result=True) -%}\n    select\n      '{{ schema_relation.database }}' as database,\n      table_name as name,\n      table_schema as schema,\n      CASE table_type\n        WHEN 'BASE TABLE' THEN 'table'\n        WHEN 'VIEW' THEN 'view'\n        WHEN 'LOCAL TEMPORARY' THEN 'table'\n        END as type\n    from information_schema.tables\n    where table_schema = '{{ schema_relation.schema }}'\n  {% endcall %}\n  {{ return(load_result('list_relations_without_caching').table) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.54345, "supported_languages": null}, "macro.dbt_duckdb.duckdb__drop_relation": {"name": "duckdb__drop_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__drop_relation", "macro_sql": "{% macro duckdb__drop_relation(relation) -%}\n  {% call statement('drop_relation', auto_begin=False) -%}\n    drop {{ relation.type }} if exists {{ relation.include(database=adapter.use_database()) }} cascade\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.543704, "supported_languages": null}, "macro.dbt_duckdb.duckdb__truncate_relation": {"name": "duckdb__truncate_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__truncate_relation", "macro_sql": "{% macro duckdb__truncate_relation(relation) -%}\n  {% call statement('truncate_relation') -%}\n    DELETE FROM {{ relation.include(database=adapter.use_database()) }} WHERE 1=1\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5438988, "supported_languages": null}, "macro.dbt_duckdb.duckdb__rename_relation": {"name": "duckdb__rename_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__rename_relation", "macro_sql": "{% macro duckdb__rename_relation(from_relation, to_relation) -%}\n  {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}\n  {% call statement('rename_relation') -%}\n    alter {{ to_relation.type }} {{ from_relation }} rename to {{ target_name }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.544176, "supported_languages": null}, "macro.dbt_duckdb.duckdb__make_temp_relation": {"name": "duckdb__make_temp_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__make_temp_relation", "macro_sql": "{% macro duckdb__make_temp_relation(base_relation, suffix) %}\n    {% set tmp_identifier = base_relation.identifier ~ suffix ~ py_current_timestring() %}\n    {% do return(base_relation.incorporate(\n                                  path={\n                                    \"identifier\": tmp_identifier,\n                                    \"schema\": none,\n                                    \"database\": none\n                                  })) -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.py_current_timestring"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.544481, "supported_languages": null}, "macro.dbt_duckdb.duckdb__current_timestamp": {"name": "duckdb__current_timestamp", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__current_timestamp", "macro_sql": "{% macro duckdb__current_timestamp() -%}\n  now()\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5445492, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_string_as_time": {"name": "duckdb__snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_string_as_time", "macro_sql": "{% macro duckdb__snapshot_string_as_time(timestamp) -%}\n    {%- set result = \"'\" ~ timestamp ~ \"'::timestamp\" -%}\n    {{ return(result) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.544718, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_get_time": {"name": "duckdb__snapshot_get_time", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_get_time", "macro_sql": "{% macro duckdb__snapshot_get_time() -%}\n  {{ current_timestamp() }}::timestamp\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5448031, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_incremental_default_sql": {"name": "duckdb__get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_incremental_default_sql", "macro_sql": "{% macro duckdb__get_incremental_default_sql(arg_dict) %}\n  {% do return(get_incremental_delete_insert_sql(arg_dict)) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_incremental_delete_insert_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.545005, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_incremental_delete_insert_sql": {"name": "duckdb__get_incremental_delete_insert_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_incremental_delete_insert_sql", "macro_sql": "{% macro duckdb__get_incremental_delete_insert_sql(arg_dict) %}\n  {% do return(get_delete_insert_merge_sql(arg_dict[\"target_relation\"].include(database=adapter.use_database()), arg_dict[\"temp_relation\"], arg_dict[\"unique_key\"], arg_dict[\"dest_columns\"])) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_delete_insert_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.54529, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_incremental_append_sql": {"name": "duckdb__get_incremental_append_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_incremental_append_sql", "macro_sql": "{% macro duckdb__get_incremental_append_sql(arg_dict) %}\n  {% do return(get_insert_into_sql(arg_dict[\"target_relation\"].include(database=adapter.use_database()), arg_dict[\"temp_relation\"], arg_dict[\"dest_columns\"])) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_insert_into_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5455391, "supported_languages": null}, "macro.dbt_duckdb.location_exists": {"name": "location_exists", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.location_exists", "macro_sql": "{% macro location_exists(location) -%}\n  {% do return(adapter.location_exists(location)) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.545696, "supported_languages": null}, "macro.dbt_duckdb.write_to_file": {"name": "write_to_file", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.write_to_file", "macro_sql": "{% macro write_to_file(relation, location, options) -%}\n  {% call statement('write_to_file') -%}\n    copy {{ relation }} to '{{ location }}' ({{ options }})\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.54589, "supported_languages": null}, "macro.dbt_duckdb.register_glue_table": {"name": "register_glue_table", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.register_glue_table", "macro_sql": "{% macro register_glue_table(register, glue_database, relation, location, format) -%}\n  {% if location.startswith(\"s3://\") and register == true %}\n    {%- set column_list = adapter.get_columns_in_relation(relation) -%}\n    {% do adapter.register_glue_table(glue_database, relation.identifier, column_list, location, format) %}\n  {% endif %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5462441, "supported_languages": null}, "macro.dbt_duckdb.render_write_options": {"name": "render_write_options", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.render_write_options", "macro_sql": "{% macro render_write_options(config) -%}\n  {% set options = config.get('options', {}) %}\n  {% for k in options %}\n    {% if options[k] is string %}\n      {% set _ = options.update({k: render(options[k])}) %}\n    {% else %}\n      {% set _ = options.update({k: render(options[k])}) %}\n    {% endif %}\n  {% endfor %}\n\n  {# legacy top-level write options #}\n  {% if config.get('format') %}\n    {% set _ = options.update({'format': render(config.get('format'))}) %}\n  {% endif %}\n  {% if config.get('delimiter') %}\n    {% set _ = options.update({'delimiter': render(config.get('delimiter'))}) %}\n  {% endif %}\n\n  {% do return(options) %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.54719, "supported_languages": null}, "macro.dbt_duckdb.materialization_table_duckdb": {"name": "materialization_table_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/table.sql", "original_file_path": "macros/materializations/table.sql", "unique_id": "macro.dbt_duckdb.materialization_table_duckdb", "macro_sql": "{% materialization table, adapter=\"duckdb\", supported_languages=['sql', 'python'] %}\n\n  {%- set language = model['language'] -%}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') %}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main', language=language) -%}\n    {{- create_table_as(False, intermediate_relation, compiled_code, language) }}\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n      {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% do create_indexes(target_relation) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.create_table_as", "macro.dbt.create_indexes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.549718, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.materialization_external_duckdb": {"name": "materialization_external_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/external.sql", "original_file_path": "macros/materializations/external.sql", "unique_id": "macro.dbt_duckdb.materialization_external_duckdb", "macro_sql": "{% materialization external, adapter=\"duckdb\", supported_languages=['sql', 'python'] %}\n\n  {%- set location = render(config.get('location', default=external_location(this, config))) -%})\n  {%- set rendered_options = render_write_options(config) -%}\n  {%- set write_options = adapter.external_write_options(location, rendered_options) -%}\n  {%- set read_location = adapter.external_read_location(location, rendered_options) -%}\n\n  -- set language - python or sql\n  {%- set language = model['language'] -%}\n\n  {%- set target_relation = this.incorporate(type='view') %}\n\n  -- Continue as normal materialization\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set temp_relation =  make_intermediate_relation(this.incorporate(type='table'), suffix='__dbt_tmp') -%}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation, suffix='__dbt_int') -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_temp_relation = load_cached_relation(temp_relation) -%}\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_temp_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('create_table', language=language) -%}\n    {{- create_table_as(False, temp_relation, compiled_code, language) }}\n  {%- endcall %}\n\n  -- write an temp relation into file\n  {{ write_to_file(temp_relation, location, write_options) }}\n  -- create a view on top of the location\n  {% call statement('main', language='sql') -%}\n    create or replace view {{ intermediate_relation.include(database=adapter.use_database()) }} as (\n        select * from '{{ read_location }}'\n    );\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n      {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n  {{ drop_relation_if_exists(temp_relation) }}\n\n  -- register table into glue\n  {%- set glue_register = config.get('glue_register', default=false) -%}\n  {%- set glue_database = render(config.get('glue_database', default='default')) -%}\n  {% do register_glue_table(glue_register, glue_database, target_relation, location, format) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt_duckdb.external_location", "macro.dbt_duckdb.render_write_options", "macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.create_table_as", "macro.dbt_duckdb.write_to_file", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt_duckdb.register_glue_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.55407, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.materialization_incremental_duckdb": {"name": "materialization_incremental_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/incremental.sql", "original_file_path": "macros/materializations/incremental.sql", "unique_id": "macro.dbt_duckdb.materialization_incremental_duckdb", "macro_sql": "{% materialization incremental, adapter=\"duckdb\", supported_languages=['sql', 'python'] -%}\n\n  {%- set language = model['language'] -%}\n\n  -- relations\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') -%}\n  {%- set temp_relation = make_temp_relation(target_relation)-%}\n  {%- set intermediate_relation = make_intermediate_relation(target_relation)-%}\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n\n  -- configs\n  {%- set unique_key = config.get('unique_key') -%}\n  {%- set full_refresh_mode = (should_full_refresh()  or existing_relation.is_view) -%}\n  {%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%}\n\n  -- the temp_ and backup_ relations should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation. This has to happen before\n  -- BEGIN, in a separate transaction\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation)-%}\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n   -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set to_drop = [] %}\n\n  {% if existing_relation is none %}\n    {% set build_sql = create_table_as(False, target_relation, compiled_code, language) %}\n  {% elif full_refresh_mode %}\n    {% set build_sql = create_table_as(False, intermediate_relation, compiled_code, language) %}\n    {% set need_swap = true %}\n  {% else %}\n    {% if language == 'python' %}\n      {% set build_python = create_table_as(False, temp_relation, compiled_code, language) %}\n      {% call statement(\"pre\", language=language) %}\n        {{- build_python }}\n      {% endcall %}\n    {% else %} {# SQL #}\n      {% do run_query(create_table_as(True, temp_relation, compiled_code, language)) %}\n    {% endif %}\n    {% do adapter.expand_target_column_types(\n             from_relation=temp_relation,\n             to_relation=target_relation) %}\n    {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#}\n    {% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %}\n    {% if not dest_columns %}\n      {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %}\n    {% endif %}\n\n    {#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#}\n    {% set incremental_strategy = config.get('incremental_strategy') or 'default' %}\n    {% set incremental_predicates = config.get('incremental_predicates', none) %}\n    {% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %}\n    {% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'predicates': incremental_predicates }) %}\n    {% set build_sql = strategy_sql_macro_func(strategy_arg_dict) %}\n    {% set language = \"sql\" %}\n\n  {% endif %}\n\n  {% call statement(\"main\", language=language) %}\n      {{- build_sql }}\n  {% endcall %}\n\n  {% if need_swap %}\n      {% do adapter.rename_relation(target_relation, backup_relation) %}\n      {% do adapter.rename_relation(intermediate_relation, target_relation) %}\n      {% do to_drop.append(backup_relation) %}\n  {% endif %}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if existing_relation is none or existing_relation.is_view or should_full_refresh() %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {% do adapter.commit() %}\n\n  {% for rel in to_drop %}\n      {% do adapter.drop_relation(rel) %}\n  {% endfor %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_temp_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.should_full_refresh", "macro.dbt.incremental_validate_on_schema_change", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.create_table_as", "macro.dbt.statement", "macro.dbt.run_query", "macro.dbt.process_schema_changes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.559038, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.duckdb__dateadd": {"name": "duckdb__dateadd", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt_duckdb.duckdb__dateadd", "macro_sql": "{% macro duckdb__dateadd(datepart, interval, from_date_or_timestamp) %}\n\n    {{ from_date_or_timestamp }} + ((interval '1 {{ datepart }}') * ({{ interval }}))\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5592582, "supported_languages": null}, "macro.dbt_duckdb.duckdb__listagg": {"name": "duckdb__listagg", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt_duckdb.duckdb__listagg", "macro_sql": "{% macro duckdb__listagg(measure, delimiter_text, order_by_clause, limit_num) -%}\n    {% if limit_num -%}\n    list_aggr(\n        (array_agg(\n            {{ measure }}\n            {% if order_by_clause -%}\n            {{ order_by_clause }}\n            {%- endif %}\n        ))[1:{{ limit_num }}],\n        'string_agg',\n        {{ delimiter_text }}\n        )\n    {%- else %}\n    string_agg(\n        {{ measure }},\n        {{ delimiter_text }}\n        {% if order_by_clause -%}\n        {{ order_by_clause }}\n        {%- endif %}\n        )\n    {%- endif %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.559789, "supported_languages": null}, "macro.dbt_duckdb.duckdb__datediff": {"name": "duckdb__datediff", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt_duckdb.duckdb__datediff", "macro_sql": "{% macro duckdb__datediff(first_date, second_date, datepart) -%}\n\n    {% if datepart == 'year' %}\n        (date_part('year', ({{second_date}})::date) - date_part('year', ({{first_date}})::date))\n    {% elif datepart == 'quarter' %}\n        ({{ datediff(first_date, second_date, 'year') }} * 4 + date_part('quarter', ({{second_date}})::date) - date_part('quarter', ({{first_date}})::date))\n    {% elif datepart == 'month' %}\n        ({{ datediff(first_date, second_date, 'year') }} * 12 + date_part('month', ({{second_date}})::date) - date_part('month', ({{first_date}})::date))\n    {% elif datepart == 'day' %}\n        (({{second_date}})::date - ({{first_date}})::date)\n    {% elif datepart == 'week' %}\n        ({{ datediff(first_date, second_date, 'day') }} / 7 + case\n            when date_part('dow', ({{first_date}})::timestamp) <= date_part('dow', ({{second_date}})::timestamp) then\n                case when {{first_date}} <= {{second_date}} then 0 else -1 end\n            else\n                case when {{first_date}} <= {{second_date}} then 1 else 0 end\n        end)\n    {% elif datepart == 'hour' %}\n        ({{ datediff(first_date, second_date, 'day') }} * 24 + date_part('hour', ({{second_date}})::timestamp) - date_part('hour', ({{first_date}})::timestamp))\n    {% elif datepart == 'minute' %}\n        ({{ datediff(first_date, second_date, 'hour') }} * 60 + date_part('minute', ({{second_date}})::timestamp) - date_part('minute', ({{first_date}})::timestamp))\n    {% elif datepart == 'second' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60 + floor(date_part('second', ({{second_date}})::timestamp)) - floor(date_part('second', ({{first_date}})::timestamp)))\n    {% elif datepart == 'millisecond' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60000 + floor(date_part('millisecond', ({{second_date}})::timestamp)) - floor(date_part('millisecond', ({{first_date}})::timestamp)))\n    {% elif datepart == 'microsecond' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60000000 + floor(date_part('microsecond', ({{second_date}})::timestamp)) - floor(date_part('microsecond', ({{first_date}})::timestamp)))\n    {% else %}\n        {{ exceptions.raise_compiler_error(\"Unsupported datepart for macro datediff in postgres: {!r}\".format(datepart)) }}\n    {% endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.datediff"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.562541, "supported_languages": null}, "macro.dbt_duckdb.duckdb__any_value": {"name": "duckdb__any_value", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt_duckdb.duckdb__any_value", "macro_sql": "{% macro duckdb__any_value(expression) -%}\n\n    arbitrary({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.562667, "supported_languages": null}, "macro.dbt_duckdb.register_upstream_external_models": {"name": "register_upstream_external_models", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/upstream.sql", "original_file_path": "macros/utils/upstream.sql", "unique_id": "macro.dbt_duckdb.register_upstream_external_models", "macro_sql": "{%- macro register_upstream_external_models() -%}\n{% if execute %}\n{% set upstream_nodes = {} %}\n{% set upstream_schemas = {} %}\n{% for node in selected_resources %}\n  {% for upstream_node in graph['nodes'][node]['depends_on']['nodes'] %}\n    {% if upstream_node not in upstream_nodes and upstream_node not in selected_resources %}\n      {% do upstream_nodes.update({upstream_node: None}) %}\n      {% set upstream = graph['nodes'].get(upstream_node) %}\n      {% if upstream\n         and upstream.resource_type in ('model', 'seed')\n         and upstream.config.materialized=='external'\n      %}\n        {%- set upstream_rel = api.Relation.create(\n          database=upstream['database'],\n          schema=upstream['schema'],\n          identifier=upstream['alias']\n        ) -%}\n        {%- set location = upstream.config.get('location', external_location(upstream, upstream.config)) -%}\n        {%- set rendered_options = render_write_options(config) -%}\n        {%- set upstream_location = adapter.external_read_location(location, rendered_options) -%}\n        {% if upstream_rel.schema not in upstream_schemas %}\n          {% call statement('main', language='sql') -%}\n            create schema if not exists {{ upstream_rel.schema }}\n          {%- endcall %}\n          {% do upstream_schemas.update({upstream_rel.schema: None}) %}\n        {% endif %}\n        {% call statement('main', language='sql') -%}\n          create or replace view {{ upstream_rel.include(database=adapter.use_database()) }} as (\n            select * from '{{ upstream_location }}'\n          );\n        {%- endcall %}\n      {%- endif %}\n    {% endif %}\n  {% endfor %}\n{% endfor %}\n{% do adapter.commit() %}\n{% endif %}\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt_duckdb.external_location", "macro.dbt_duckdb.render_write_options", "macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.564817, "supported_languages": null}, "macro.dbt_duckdb.duckdb__split_part": {"name": "duckdb__split_part", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/splitpart.sql", "original_file_path": "macros/utils/splitpart.sql", "unique_id": "macro.dbt_duckdb.duckdb__split_part", "macro_sql": "{% macro duckdb__split_part(string_text, delimiter_text, part_number) %}\n\n  {% if part_number >= 0 %}\n    coalesce(string_split({{ string_text }}, {{ delimiter_text }})[ {{ part_number }} ], '')\n  {% else %}\n    {{ dbt._split_part_negative(string_text, delimiter_text, part_number) }}\n  {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt._split_part_negative"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.565182, "supported_languages": null}, "macro.dbt_duckdb.duckdb__last_day": {"name": "duckdb__last_day", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/lastday.sql", "original_file_path": "macros/utils/lastday.sql", "unique_id": "macro.dbt_duckdb.duckdb__last_day", "macro_sql": "{% macro duckdb__last_day(date, datepart) -%}\n\n    {%- if datepart == 'quarter' -%}\n    -- duckdb dateadd does not support quarter interval.\n    cast(\n        {{dbt.dateadd('day', '-1',\n        dbt.dateadd('month', '3', dbt.date_trunc(datepart, date))\n        )}}\n        as date)\n    {%- else -%}\n    {{dbt.default_last_day(date, datepart)}}\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.dateadd", "macro.dbt.date_trunc", "macro.dbt.default_last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.565612, "supported_languages": null}, "macro.dbt_duckdb.external_location": {"name": "external_location", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/external_location.sql", "original_file_path": "macros/utils/external_location.sql", "unique_id": "macro.dbt_duckdb.external_location", "macro_sql": "{%- macro external_location(relation, config) -%}\n  {%- if config.get('options', {}).get('partition_by') is none -%}\n    {%- set format = config.get('format', 'parquet') -%}\n    {{- adapter.external_root() }}/{{ relation.identifier }}.{{ format }}\n  {%- else -%}\n    {{- adapter.external_root() }}/{{ relation.identifier }}\n  {%- endif -%}\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.566093, "supported_languages": null}, "macro.dbt.run_hooks": {"name": "run_hooks", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.run_hooks", "macro_sql": "{% macro run_hooks(hooks, inside_transaction=True) %}\n  {% for hook in hooks | selectattr('transaction', 'equalto', inside_transaction)  %}\n    {% if not inside_transaction and loop.first %}\n      {% call statement(auto_begin=inside_transaction) %}\n        commit;\n      {% endcall %}\n    {% endif %}\n    {% set rendered = render(hook.get('sql')) | trim %}\n    {% if (rendered | length) > 0 %}\n      {% call statement(auto_begin=inside_transaction) %}\n        {{ rendered }}\n      {% endcall %}\n    {% endif %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.567016, "supported_languages": null}, "macro.dbt.make_hook_config": {"name": "make_hook_config", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.make_hook_config", "macro_sql": "{% macro make_hook_config(sql, inside_transaction) %}\n    {{ tojson({\"sql\": sql, \"transaction\": inside_transaction}) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5671868, "supported_languages": null}, "macro.dbt.before_begin": {"name": "before_begin", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.before_begin", "macro_sql": "{% macro before_begin(sql) %}\n    {{ make_hook_config(sql, inside_transaction=False) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.567308, "supported_languages": null}, "macro.dbt.in_transaction": {"name": "in_transaction", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.in_transaction", "macro_sql": "{% macro in_transaction(sql) %}\n    {{ make_hook_config(sql, inside_transaction=True) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.567431, "supported_languages": null}, "macro.dbt.after_commit": {"name": "after_commit", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.after_commit", "macro_sql": "{% macro after_commit(sql) %}\n    {{ make_hook_config(sql, inside_transaction=False) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.567552, "supported_languages": null}, "macro.dbt.set_sql_header": {"name": "set_sql_header", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.set_sql_header", "macro_sql": "{% macro set_sql_header(config) -%}\n  {{ config.set('sql_header', caller()) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.567872, "supported_languages": null}, "macro.dbt.should_full_refresh": {"name": "should_full_refresh", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.should_full_refresh", "macro_sql": "{% macro should_full_refresh() %}\n  {% set config_full_refresh = config.get('full_refresh') %}\n  {% if config_full_refresh is none %}\n    {% set config_full_refresh = flags.FULL_REFRESH %}\n  {% endif %}\n  {% do return(config_full_refresh) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.568131, "supported_languages": null}, "macro.dbt.should_store_failures": {"name": "should_store_failures", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.should_store_failures", "macro_sql": "{% macro should_store_failures() %}\n  {% set config_store_failures = config.get('store_failures') %}\n  {% if config_store_failures is none %}\n    {% set config_store_failures = flags.STORE_FAILURES %}\n  {% endif %}\n  {% do return(config_store_failures) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.568392, "supported_languages": null}, "macro.dbt.snapshot_merge_sql": {"name": "snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot_merge.sql", "original_file_path": "macros/materializations/snapshots/snapshot_merge.sql", "unique_id": "macro.dbt.snapshot_merge_sql", "macro_sql": "{% macro snapshot_merge_sql(target, source, insert_cols) -%}\n  {{ adapter.dispatch('snapshot_merge_sql', 'dbt')(target, source, insert_cols) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.568773, "supported_languages": null}, "macro.dbt.default__snapshot_merge_sql": {"name": "default__snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot_merge.sql", "original_file_path": "macros/materializations/snapshots/snapshot_merge.sql", "unique_id": "macro.dbt.default__snapshot_merge_sql", "macro_sql": "{% macro default__snapshot_merge_sql(target, source, insert_cols) -%}\n    {%- set insert_cols_csv = insert_cols | join(', ') -%}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n    using {{ source }} as DBT_INTERNAL_SOURCE\n    on DBT_INTERNAL_SOURCE.dbt_scd_id = DBT_INTERNAL_DEST.dbt_scd_id\n\n    when matched\n     and DBT_INTERNAL_DEST.dbt_valid_to is null\n     and DBT_INTERNAL_SOURCE.dbt_change_type in ('update', 'delete')\n        then update\n        set dbt_valid_to = DBT_INTERNAL_SOURCE.dbt_valid_to\n\n    when not matched\n     and DBT_INTERNAL_SOURCE.dbt_change_type = 'insert'\n        then insert ({{ insert_cols_csv }})\n        values ({{ insert_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.569004, "supported_languages": null}, "macro.dbt.strategy_dispatch": {"name": "strategy_dispatch", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.strategy_dispatch", "macro_sql": "{% macro strategy_dispatch(name) -%}\n{% set original_name = name %}\n  {% if '.' in name %}\n    {% set package_name, name = name.split(\".\", 1) %}\n  {% else %}\n    {% set package_name = none %}\n  {% endif %}\n\n  {% if package_name is none %}\n    {% set package_context = context %}\n  {% elif package_name in context %}\n    {% set package_context = context[package_name] %}\n  {% else %}\n    {% set error_msg %}\n        Could not find package '{{package_name}}', called with '{{original_name}}'\n    {% endset %}\n    {{ exceptions.raise_compiler_error(error_msg | trim) }}\n  {% endif %}\n\n  {%- set search_name = 'snapshot_' ~ name ~ '_strategy' -%}\n\n  {% if search_name not in package_context %}\n    {% set error_msg %}\n        The specified strategy macro '{{name}}' was not found in package '{{ package_name }}'\n    {% endset %}\n    {{ exceptions.raise_compiler_error(error_msg | trim) }}\n  {% endif %}\n  {{ return(package_context[search_name]) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.572018, "supported_languages": null}, "macro.dbt.snapshot_hash_arguments": {"name": "snapshot_hash_arguments", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_hash_arguments", "macro_sql": "{% macro snapshot_hash_arguments(args) -%}\n  {{ adapter.dispatch('snapshot_hash_arguments', 'dbt')(args) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.572164, "supported_languages": null}, "macro.dbt.default__snapshot_hash_arguments": {"name": "default__snapshot_hash_arguments", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.default__snapshot_hash_arguments", "macro_sql": "{% macro default__snapshot_hash_arguments(args) -%}\n    md5({%- for arg in args -%}\n        coalesce(cast({{ arg }} as varchar ), '')\n        {% if not loop.last %} || '|' || {% endif %}\n    {%- endfor -%})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5723531, "supported_languages": null}, "macro.dbt.snapshot_timestamp_strategy": {"name": "snapshot_timestamp_strategy", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_timestamp_strategy", "macro_sql": "{% macro snapshot_timestamp_strategy(node, snapshotted_rel, current_rel, config, target_exists) %}\n    {% set primary_key = config['unique_key'] %}\n    {% set updated_at = config['updated_at'] %}\n    {% set invalidate_hard_deletes = config.get('invalidate_hard_deletes', false) %}\n\n    {#/*\n        The snapshot relation might not have an {{ updated_at }} value if the\n        snapshot strategy is changed from `check` to `timestamp`. We\n        should use a dbt-created column for the comparison in the snapshot\n        table instead of assuming that the user-supplied {{ updated_at }}\n        will be present in the historical data.\n\n        See https://github.com/dbt-labs/dbt-core/issues/2350\n    */ #}\n    {% set row_changed_expr -%}\n        ({{ snapshotted_rel }}.dbt_valid_from < {{ current_rel }}.{{ updated_at }})\n    {%- endset %}\n\n    {% set scd_id_expr = snapshot_hash_arguments([primary_key, updated_at]) %}\n\n    {% do return({\n        \"unique_key\": primary_key,\n        \"updated_at\": updated_at,\n        \"row_changed\": row_changed_expr,\n        \"scd_id\": scd_id_expr,\n        \"invalidate_hard_deletes\": invalidate_hard_deletes\n    }) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.572973, "supported_languages": null}, "macro.dbt.snapshot_string_as_time": {"name": "snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_string_as_time", "macro_sql": "{% macro snapshot_string_as_time(timestamp) -%}\n    {{ adapter.dispatch('snapshot_string_as_time', 'dbt')(timestamp) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_string_as_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.573117, "supported_languages": null}, "macro.dbt.default__snapshot_string_as_time": {"name": "default__snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.default__snapshot_string_as_time", "macro_sql": "{% macro default__snapshot_string_as_time(timestamp) %}\n    {% do exceptions.raise_not_implemented(\n        'snapshot_string_as_time macro not implemented for adapter '+adapter.type()\n    ) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.573271, "supported_languages": null}, "macro.dbt.snapshot_check_all_get_existing_columns": {"name": "snapshot_check_all_get_existing_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_check_all_get_existing_columns", "macro_sql": "{% macro snapshot_check_all_get_existing_columns(node, target_exists, check_cols_config) -%}\n    {%- if not target_exists -%}\n        {#-- no table yet -> return whatever the query does --#}\n        {{ return((false, query_columns)) }}\n    {%- endif -%}\n\n    {#-- handle any schema changes --#}\n    {%- set target_relation = adapter.get_relation(database=node.database, schema=node.schema, identifier=node.alias) -%}\n\n    {% if check_cols_config == 'all' %}\n        {%- set query_columns = get_columns_in_query(node['compiled_code']) -%}\n\n    {% elif check_cols_config is iterable and (check_cols_config | length) > 0 %}\n        {#-- query for proper casing/quoting, to support comparison below --#}\n        {%- set select_check_cols_from_target -%}\n          select {{ check_cols_config | join(', ') }} from ({{ node['compiled_code'] }}) subq\n        {%- endset -%}\n        {% set query_columns = get_columns_in_query(select_check_cols_from_target) %}\n\n    {% else %}\n        {% do exceptions.raise_compiler_error(\"Invalid value for 'check_cols': \" ~ check_cols_config) %}\n    {% endif %}\n\n    {%- set existing_cols = adapter.get_columns_in_relation(target_relation) | map(attribute = 'name') | list -%}\n    {%- set ns = namespace() -%} {#-- handle for-loop scoping with a namespace --#}\n    {%- set ns.column_added = false -%}\n\n    {%- set intersection = [] -%}\n    {%- for col in query_columns -%}\n        {%- if col in existing_cols -%}\n            {%- do intersection.append(adapter.quote(col)) -%}\n        {%- else -%}\n            {% set ns.column_added = true %}\n        {%- endif -%}\n    {%- endfor -%}\n    {{ return((ns.column_added, intersection)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_columns_in_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.574463, "supported_languages": null}, "macro.dbt.snapshot_check_strategy": {"name": "snapshot_check_strategy", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_check_strategy", "macro_sql": "{% macro snapshot_check_strategy(node, snapshotted_rel, current_rel, config, target_exists) %}\n    {% set check_cols_config = config['check_cols'] %}\n    {% set primary_key = config['unique_key'] %}\n    {% set invalidate_hard_deletes = config.get('invalidate_hard_deletes', false) %}\n    {% set updated_at = config.get('updated_at', snapshot_get_time()) %}\n\n    {% set column_added = false %}\n\n    {% set column_added, check_cols = snapshot_check_all_get_existing_columns(node, target_exists, check_cols_config) %}\n\n    {%- set row_changed_expr -%}\n    (\n    {%- if column_added -%}\n        {{ get_true_sql() }}\n    {%- else -%}\n    {%- for col in check_cols -%}\n        {{ snapshotted_rel }}.{{ col }} != {{ current_rel }}.{{ col }}\n        or\n        (\n            (({{ snapshotted_rel }}.{{ col }} is null) and not ({{ current_rel }}.{{ col }} is null))\n            or\n            ((not {{ snapshotted_rel }}.{{ col }} is null) and ({{ current_rel }}.{{ col }} is null))\n        )\n        {%- if not loop.last %} or {% endif -%}\n    {%- endfor -%}\n    {%- endif -%}\n    )\n    {%- endset %}\n\n    {% set scd_id_expr = snapshot_hash_arguments([primary_key, updated_at]) %}\n\n    {% do return({\n        \"unique_key\": primary_key,\n        \"updated_at\": updated_at,\n        \"row_changed\": row_changed_expr,\n        \"scd_id\": scd_id_expr,\n        \"invalidate_hard_deletes\": invalidate_hard_deletes\n    }) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_get_time", "macro.dbt.snapshot_check_all_get_existing_columns", "macro.dbt.get_true_sql", "macro.dbt.snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5756218, "supported_languages": null}, "macro.dbt.create_columns": {"name": "create_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.create_columns", "macro_sql": "{% macro create_columns(relation, columns) %}\n  {{ adapter.dispatch('create_columns', 'dbt')(relation, columns) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579034, "supported_languages": null}, "macro.dbt.default__create_columns": {"name": "default__create_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__create_columns", "macro_sql": "{% macro default__create_columns(relation, columns) %}\n  {% for column in columns %}\n    {% call statement() %}\n      alter table {{ relation }} add column \"{{ column.name }}\" {{ column.data_type }};\n    {% endcall %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579274, "supported_languages": null}, "macro.dbt.post_snapshot": {"name": "post_snapshot", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.post_snapshot", "macro_sql": "{% macro post_snapshot(staging_relation) %}\n  {{ adapter.dispatch('post_snapshot', 'dbt')(staging_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__post_snapshot"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579415, "supported_languages": null}, "macro.dbt.default__post_snapshot": {"name": "default__post_snapshot", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__post_snapshot", "macro_sql": "{% macro default__post_snapshot(staging_relation) %}\n    {# no-op #}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579489, "supported_languages": null}, "macro.dbt.get_true_sql": {"name": "get_true_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.get_true_sql", "macro_sql": "{% macro get_true_sql() %}\n  {{ adapter.dispatch('get_true_sql', 'dbt')() }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_true_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579612, "supported_languages": null}, "macro.dbt.default__get_true_sql": {"name": "default__get_true_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__get_true_sql", "macro_sql": "{% macro default__get_true_sql() %}\n    {{ return('TRUE') }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579707, "supported_languages": null}, "macro.dbt.snapshot_staging_table": {"name": "snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.snapshot_staging_table", "macro_sql": "{% macro snapshot_staging_table(strategy, source_sql, target_relation) -%}\n  {{ adapter.dispatch('snapshot_staging_table', 'dbt')(strategy, source_sql, target_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__snapshot_staging_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.579885, "supported_languages": null}, "macro.dbt.default__snapshot_staging_table": {"name": "default__snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__snapshot_staging_table", "macro_sql": "{% macro default__snapshot_staging_table(strategy, source_sql, target_relation) -%}\n\n    with snapshot_query as (\n\n        {{ source_sql }}\n\n    ),\n\n    snapshotted_data as (\n\n        select *,\n            {{ strategy.unique_key }} as dbt_unique_key\n\n        from {{ target_relation }}\n        where dbt_valid_to is null\n\n    ),\n\n    insertions_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key,\n            {{ strategy.updated_at }} as dbt_updated_at,\n            {{ strategy.updated_at }} as dbt_valid_from,\n            nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) as dbt_valid_to,\n            {{ strategy.scd_id }} as dbt_scd_id\n\n        from snapshot_query\n    ),\n\n    updates_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key,\n            {{ strategy.updated_at }} as dbt_updated_at,\n            {{ strategy.updated_at }} as dbt_valid_from,\n            {{ strategy.updated_at }} as dbt_valid_to\n\n        from snapshot_query\n    ),\n\n    {%- if strategy.invalidate_hard_deletes %}\n\n    deletes_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key\n        from snapshot_query\n    ),\n    {% endif %}\n\n    insertions as (\n\n        select\n            'insert' as dbt_change_type,\n            source_data.*\n\n        from insertions_source_data as source_data\n        left outer join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where snapshotted_data.dbt_unique_key is null\n           or (\n                snapshotted_data.dbt_unique_key is not null\n            and (\n                {{ strategy.row_changed }}\n            )\n        )\n\n    ),\n\n    updates as (\n\n        select\n            'update' as dbt_change_type,\n            source_data.*,\n            snapshotted_data.dbt_scd_id\n\n        from updates_source_data as source_data\n        join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where (\n            {{ strategy.row_changed }}\n        )\n    )\n\n    {%- if strategy.invalidate_hard_deletes -%}\n    ,\n\n    deletes as (\n\n        select\n            'delete' as dbt_change_type,\n            source_data.*,\n            {{ snapshot_get_time() }} as dbt_valid_from,\n            {{ snapshot_get_time() }} as dbt_updated_at,\n            {{ snapshot_get_time() }} as dbt_valid_to,\n            snapshotted_data.dbt_scd_id\n\n        from snapshotted_data\n        left join deletes_source_data as source_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where source_data.dbt_unique_key is null\n    )\n    {%- endif %}\n\n    select * from insertions\n    union all\n    select * from updates\n    {%- if strategy.invalidate_hard_deletes %}\n    union all\n    select * from deletes\n    {%- endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_get_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.58063, "supported_languages": null}, "macro.dbt.build_snapshot_table": {"name": "build_snapshot_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.build_snapshot_table", "macro_sql": "{% macro build_snapshot_table(strategy, sql) -%}\n  {{ adapter.dispatch('build_snapshot_table', 'dbt')(strategy, sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__build_snapshot_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.580791, "supported_languages": null}, "macro.dbt.default__build_snapshot_table": {"name": "default__build_snapshot_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__build_snapshot_table", "macro_sql": "{% macro default__build_snapshot_table(strategy, sql) %}\n\n    select *,\n        {{ strategy.scd_id }} as dbt_scd_id,\n        {{ strategy.updated_at }} as dbt_updated_at,\n        {{ strategy.updated_at }} as dbt_valid_from,\n        nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) as dbt_valid_to\n    from (\n        {{ sql }}\n    ) sbq\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.581003, "supported_languages": null}, "macro.dbt.build_snapshot_staging_table": {"name": "build_snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.build_snapshot_staging_table", "macro_sql": "{% macro build_snapshot_staging_table(strategy, sql, target_relation) %}\n    {% set temp_relation = make_temp_relation(target_relation) %}\n\n    {% set select = snapshot_staging_table(strategy, sql, target_relation) %}\n\n    {% call statement('build_snapshot_staging_relation') %}\n        {{ create_table_as(True, temp_relation, select) }}\n    {% endcall %}\n\n    {% do return(temp_relation) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_temp_relation", "macro.dbt.snapshot_staging_table", "macro.dbt.statement", "macro.dbt.create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.581364, "supported_languages": null}, "macro.dbt.materialization_snapshot_default": {"name": "materialization_snapshot_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot.sql", "original_file_path": "macros/materializations/snapshots/snapshot.sql", "unique_id": "macro.dbt.materialization_snapshot_default", "macro_sql": "{% materialization snapshot, default %}\n  {%- set config = model['config'] -%}\n\n  {%- set target_table = model.get('alias', model.get('name')) -%}\n\n  {%- set strategy_name = config.get('strategy') -%}\n  {%- set unique_key = config.get('unique_key') %}\n  -- grab current tables grants config for comparision later on\n  {%- set grant_config = config.get('grants') -%}\n\n  {% set target_relation_exists, target_relation = get_or_create_relation(\n          database=model.database,\n          schema=model.schema,\n          identifier=target_table,\n          type='table') -%}\n\n  {%- if not target_relation.is_table -%}\n    {% do exceptions.relation_wrong_type(target_relation, 'table') %}\n  {%- endif -%}\n\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set strategy_macro = strategy_dispatch(strategy_name) %}\n  {% set strategy = strategy_macro(model, \"snapshotted_data\", \"source_data\", config, target_relation_exists) %}\n\n  {% if not target_relation_exists %}\n\n      {% set build_sql = build_snapshot_table(strategy, model['compiled_code']) %}\n      {% set final_sql = create_table_as(False, target_relation, build_sql) %}\n\n  {% else %}\n\n      {{ adapter.valid_snapshot_target(target_relation) }}\n\n      {% set staging_table = build_snapshot_staging_table(strategy, sql, target_relation) %}\n\n      -- this may no-op if the database does not require column expansion\n      {% do adapter.expand_target_column_types(from_relation=staging_table,\n                                               to_relation=target_relation) %}\n\n      {% set missing_columns = adapter.get_missing_columns(staging_table, target_relation)\n                                   | rejectattr('name', 'equalto', 'dbt_change_type')\n                                   | rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')\n                                   | rejectattr('name', 'equalto', 'dbt_unique_key')\n                                   | rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')\n                                   | list %}\n\n      {% do create_columns(target_relation, missing_columns) %}\n\n      {% set source_columns = adapter.get_columns_in_relation(staging_table)\n                                   | rejectattr('name', 'equalto', 'dbt_change_type')\n                                   | rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')\n                                   | rejectattr('name', 'equalto', 'dbt_unique_key')\n                                   | rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')\n                                   | list %}\n\n      {% set quoted_source_columns = [] %}\n      {% for column in source_columns %}\n        {% do quoted_source_columns.append(adapter.quote(column.name)) %}\n      {% endfor %}\n\n      {% set final_sql = snapshot_merge_sql(\n            target = target_relation,\n            source = staging_table,\n            insert_cols = quoted_source_columns\n         )\n      %}\n\n  {% endif %}\n\n  {% call statement('main') %}\n      {{ final_sql }}\n  {% endcall %}\n\n  {% set should_revoke = should_revoke(target_relation_exists, full_refresh_mode=False) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if not target_relation_exists %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {{ adapter.commit() }}\n\n  {% if staging_table is defined %}\n      {% do post_snapshot(staging_table) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.get_or_create_relation", "macro.dbt.run_hooks", "macro.dbt.strategy_dispatch", "macro.dbt.build_snapshot_table", "macro.dbt.create_table_as", "macro.dbt.build_snapshot_staging_table", "macro.dbt.create_columns", "macro.dbt.snapshot_merge_sql", "macro.dbt.statement", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes", "macro.dbt.post_snapshot"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5864599, "supported_languages": ["sql"]}, "macro.dbt.materialization_test_default": {"name": "materialization_test_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/test.sql", "original_file_path": "macros/materializations/tests/test.sql", "unique_id": "macro.dbt.materialization_test_default", "macro_sql": "{%- materialization test, default -%}\n\n  {% set relations = [] %}\n\n  {% if should_store_failures() %}\n\n    {% set identifier = model['alias'] %}\n    {% set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) %}\n    {% set target_relation = api.Relation.create(\n        identifier=identifier, schema=schema, database=database, type='table') -%} %}\n\n    {% if old_relation %}\n        {% do adapter.drop_relation(old_relation) %}\n    {% endif %}\n\n    {% call statement(auto_begin=True) %}\n        {{ create_table_as(False, target_relation, sql) }}\n    {% endcall %}\n\n    {% do relations.append(target_relation) %}\n\n    {% set main_sql %}\n        select *\n        from {{ target_relation }}\n    {% endset %}\n\n    {{ adapter.commit() }}\n\n  {% else %}\n\n      {% set main_sql = sql %}\n\n  {% endif %}\n\n  {% set limit = config.get('limit') %}\n  {% set fail_calc = config.get('fail_calc') %}\n  {% set warn_if = config.get('warn_if') %}\n  {% set error_if = config.get('error_if') %}\n\n  {% call statement('main', fetch_result=True) -%}\n\n    {{ get_test_sql(main_sql, fail_calc, warn_if, error_if, limit)}}\n\n  {%- endcall %}\n\n  {{ return({'relations': relations}) }}\n\n{%- endmaterialization -%}", "depends_on": {"macros": ["macro.dbt.should_store_failures", "macro.dbt.statement", "macro.dbt.create_table_as", "macro.dbt.get_test_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5882041, "supported_languages": ["sql"]}, "macro.dbt.get_test_sql": {"name": "get_test_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/helpers.sql", "original_file_path": "macros/materializations/tests/helpers.sql", "unique_id": "macro.dbt.get_test_sql", "macro_sql": "{% macro get_test_sql(main_sql, fail_calc, warn_if, error_if, limit) -%}\n  {{ adapter.dispatch('get_test_sql', 'dbt')(main_sql, fail_calc, warn_if, error_if, limit) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_test_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.588593, "supported_languages": null}, "macro.dbt.default__get_test_sql": {"name": "default__get_test_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/helpers.sql", "original_file_path": "macros/materializations/tests/helpers.sql", "unique_id": "macro.dbt.default__get_test_sql", "macro_sql": "{% macro default__get_test_sql(main_sql, fail_calc, warn_if, error_if, limit) -%}\n    select\n      {{ fail_calc }} as failures,\n      {{ fail_calc }} {{ warn_if }} as should_warn,\n      {{ fail_calc }} {{ error_if }} as should_error\n    from (\n      {{ main_sql }}\n      {{ \"limit \" ~ limit if limit != none }}\n    ) dbt_internal_test\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.588854, "supported_languages": null}, "macro.dbt.get_where_subquery": {"name": "get_where_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/where_subquery.sql", "original_file_path": "macros/materializations/tests/where_subquery.sql", "unique_id": "macro.dbt.get_where_subquery", "macro_sql": "{% macro get_where_subquery(relation) -%}\n    {% do return(adapter.dispatch('get_where_subquery', 'dbt')(relation)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_where_subquery"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.589171, "supported_languages": null}, "macro.dbt.default__get_where_subquery": {"name": "default__get_where_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/where_subquery.sql", "original_file_path": "macros/materializations/tests/where_subquery.sql", "unique_id": "macro.dbt.default__get_where_subquery", "macro_sql": "{% macro default__get_where_subquery(relation) -%}\n    {% set where = config.get('where', '') %}\n    {% if where %}\n        {%- set filtered -%}\n            (select * from {{ relation }} where {{ where }}) dbt_subquery\n        {%- endset -%}\n        {% do return(filtered) %}\n    {%- else -%}\n        {% do return(relation) %}\n    {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.589488, "supported_languages": null}, "macro.dbt.get_quoted_csv": {"name": "get_quoted_csv", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.get_quoted_csv", "macro_sql": "{% macro get_quoted_csv(column_names) %}\n\n    {% set quoted = [] %}\n    {% for col in column_names -%}\n        {%- do quoted.append(adapter.quote(col)) -%}\n    {%- endfor %}\n\n    {%- set dest_cols_csv = quoted | join(', ') -%}\n    {{ return(dest_cols_csv) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5908349, "supported_languages": null}, "macro.dbt.diff_columns": {"name": "diff_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.diff_columns", "macro_sql": "{% macro diff_columns(source_columns, target_columns) %}\n\n  {% set result = [] %}\n  {% set source_names = source_columns | map(attribute = 'column') | list %}\n  {% set target_names = target_columns | map(attribute = 'column') | list %}\n\n   {# --check whether the name attribute exists in the target - this does not perform a data type check #}\n   {% for sc in source_columns %}\n     {% if sc.name not in target_names %}\n        {{ result.append(sc) }}\n     {% endif %}\n   {% endfor %}\n\n  {{ return(result) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.591302, "supported_languages": null}, "macro.dbt.diff_column_data_types": {"name": "diff_column_data_types", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.diff_column_data_types", "macro_sql": "{% macro diff_column_data_types(source_columns, target_columns) %}\n\n  {% set result = [] %}\n  {% for sc in source_columns %}\n    {% set tc = target_columns | selectattr(\"name\", \"equalto\", sc.name) | list | first %}\n    {% if tc %}\n      {% if sc.data_type != tc.data_type and not sc.can_expand_to(other_column=tc) %}\n        {{ result.append( { 'column_name': tc.name, 'new_type': sc.data_type } ) }}\n      {% endif %}\n    {% endif %}\n  {% endfor %}\n\n  {{ return(result) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5918689, "supported_languages": null}, "macro.dbt.get_merge_update_columns": {"name": "get_merge_update_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.get_merge_update_columns", "macro_sql": "{% macro get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) %}\n  {{ return(adapter.dispatch('get_merge_update_columns', 'dbt')(merge_update_columns, merge_exclude_columns, dest_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_merge_update_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.5920708, "supported_languages": null}, "macro.dbt.default__get_merge_update_columns": {"name": "default__get_merge_update_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.default__get_merge_update_columns", "macro_sql": "{% macro default__get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) %}\n  {%- set default_cols = dest_columns | map(attribute=\"quoted\") | list -%}\n\n  {%- if merge_update_columns and merge_exclude_columns -%}\n    {{ exceptions.raise_compiler_error(\n        'Model cannot specify merge_update_columns and merge_exclude_columns. Please update model to use only one config'\n    )}}\n  {%- elif merge_update_columns -%}\n    {%- set update_columns = merge_update_columns -%}\n  {%- elif merge_exclude_columns -%}\n    {%- set update_columns = [] -%}\n    {%- for column in dest_columns -%}\n      {% if column.column | lower not in merge_exclude_columns | map(\"lower\") | list %}\n        {%- do update_columns.append(column.quoted) -%}\n      {% endif %}\n    {%- endfor -%}\n  {%- else -%}\n    {%- set update_columns = default_cols -%}\n  {%- endif -%}\n\n  {{ return(update_columns) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.592672, "supported_languages": null}, "macro.dbt.get_merge_sql": {"name": "get_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_merge_sql", "macro_sql": "{% macro get_merge_sql(target, source, unique_key, dest_columns, incremental_predicates=none) -%}\n   -- back compat for old kwarg name\n  {% set incremental_predicates = kwargs.get('predicates', incremental_predicates) %}\n  {{ adapter.dispatch('get_merge_sql', 'dbt')(target, source, unique_key, dest_columns, incremental_predicates) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.597745, "supported_languages": null}, "macro.dbt.default__get_merge_sql": {"name": "default__get_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_merge_sql", "macro_sql": "{% macro default__get_merge_sql(target, source, unique_key, dest_columns, incremental_predicates=none) -%}\n    {%- set predicates = [] if incremental_predicates is none else [] + incremental_predicates -%}\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n    {%- set merge_update_columns = config.get('merge_update_columns') -%}\n    {%- set merge_exclude_columns = config.get('merge_exclude_columns') -%}\n    {%- set update_columns = get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) -%}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {% if unique_key %}\n        {% if unique_key is sequence and unique_key is not mapping and unique_key is not string %}\n            {% for key in unique_key %}\n                {% set this_key_match %}\n                    DBT_INTERNAL_SOURCE.{{ key }} = DBT_INTERNAL_DEST.{{ key }}\n                {% endset %}\n                {% do predicates.append(this_key_match) %}\n            {% endfor %}\n        {% else %}\n            {% set unique_key_match %}\n                DBT_INTERNAL_SOURCE.{{ unique_key }} = DBT_INTERNAL_DEST.{{ unique_key }}\n            {% endset %}\n            {% do predicates.append(unique_key_match) %}\n        {% endif %}\n    {% else %}\n        {% do predicates.append('FALSE') %}\n    {% endif %}\n\n    {{ sql_header if sql_header is not none }}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n        using {{ source }} as DBT_INTERNAL_SOURCE\n        on {{\"(\" ~ predicates | join(\") and (\") ~ \")\"}}\n\n    {% if unique_key %}\n    when matched then update set\n        {% for column_name in update_columns -%}\n            {{ column_name }} = DBT_INTERNAL_SOURCE.{{ column_name }}\n            {%- if not loop.last %}, {%- endif %}\n        {%- endfor %}\n    {% endif %}\n\n    when not matched then insert\n        ({{ dest_cols_csv }})\n    values\n        ({{ dest_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv", "macro.dbt.get_merge_update_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.599158, "supported_languages": null}, "macro.dbt.get_delete_insert_merge_sql": {"name": "get_delete_insert_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_delete_insert_merge_sql", "macro_sql": "{% macro get_delete_insert_merge_sql(target, source, unique_key, dest_columns, incremental_predicates) -%}\n  {{ adapter.dispatch('get_delete_insert_merge_sql', 'dbt')(target, source, unique_key, dest_columns, incremental_predicates) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_delete_insert_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.599381, "supported_languages": null}, "macro.dbt.default__get_delete_insert_merge_sql": {"name": "default__get_delete_insert_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_delete_insert_merge_sql", "macro_sql": "{% macro default__get_delete_insert_merge_sql(target, source, unique_key, dest_columns, incremental_predicates) -%}\n\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n\n    {% if unique_key %}\n        {% if unique_key is sequence and unique_key is not string %}\n            delete from {{target }}\n            using {{ source }}\n            where (\n                {% for key in unique_key %}\n                    {{ source }}.{{ key }} = {{ target }}.{{ key }}\n                    {{ \"and \" if not loop.last}}\n                {% endfor %}\n                {% if incremental_predicates %}\n                    {% for predicate in incremental_predicates %}\n                        and {{ predicate }}\n                    {% endfor %}\n                {% endif %}\n            );\n        {% else %}\n            delete from {{ target }}\n            where (\n                {{ unique_key }}) in (\n                select ({{ unique_key }})\n                from {{ source }}\n            )\n            {%- if incremental_predicates %}\n                {% for predicate in incremental_predicates %}\n                    and {{ predicate }}\n                {% endfor %}\n            {%- endif -%};\n\n        {% endif %}\n    {% endif %}\n\n    insert into {{ target }} ({{ dest_cols_csv }})\n    (\n        select {{ dest_cols_csv }}\n        from {{ source }}\n    )\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.600228, "supported_languages": null}, "macro.dbt.get_insert_overwrite_merge_sql": {"name": "get_insert_overwrite_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_insert_overwrite_merge_sql", "macro_sql": "{% macro get_insert_overwrite_merge_sql(target, source, dest_columns, predicates, include_sql_header=false) -%}\n  {{ adapter.dispatch('get_insert_overwrite_merge_sql', 'dbt')(target, source, dest_columns, predicates, include_sql_header) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_insert_overwrite_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.600458, "supported_languages": null}, "macro.dbt.default__get_insert_overwrite_merge_sql": {"name": "default__get_insert_overwrite_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_insert_overwrite_merge_sql", "macro_sql": "{% macro default__get_insert_overwrite_merge_sql(target, source, dest_columns, predicates, include_sql_header) -%}\n    {#-- The only time include_sql_header is True: --#}\n    {#-- BigQuery + insert_overwrite strategy + \"static\" partitions config --#}\n    {#-- We should consider including the sql header at the materialization level instead --#}\n\n    {%- set predicates = [] if predicates is none else [] + predicates -%}\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {{ sql_header if sql_header is not none and include_sql_header }}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n        using {{ source }} as DBT_INTERNAL_SOURCE\n        on FALSE\n\n    when not matched by source\n        {% if predicates %} and {{ predicates | join(' and ') }} {% endif %}\n        then delete\n\n    when not matched then insert\n        ({{ dest_cols_csv }})\n    values\n        ({{ dest_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6010041, "supported_languages": null}, "macro.dbt.is_incremental": {"name": "is_incremental", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/is_incremental.sql", "original_file_path": "macros/materializations/models/incremental/is_incremental.sql", "unique_id": "macro.dbt.is_incremental", "macro_sql": "{% macro is_incremental() %}\n    {#-- do not run introspective queries in parsing #}\n    {% if not execute %}\n        {{ return(False) }}\n    {% else %}\n        {% set relation = adapter.get_relation(this.database, this.schema, this.table) %}\n        {{ return(relation is not none\n                  and relation.type == 'table'\n                  and model.config.materialized == 'incremental'\n                  and not should_full_refresh()) }}\n    {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.should_full_refresh"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.60154, "supported_languages": null}, "macro.dbt.get_incremental_append_sql": {"name": "get_incremental_append_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_append_sql", "macro_sql": "{% macro get_incremental_append_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_append_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_incremental_append_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.602304, "supported_languages": null}, "macro.dbt.default__get_incremental_append_sql": {"name": "default__get_incremental_append_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_append_sql", "macro_sql": "{% macro default__get_incremental_append_sql(arg_dict) %}\n\n  {% do return(get_insert_into_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"dest_columns\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_insert_into_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.602527, "supported_languages": null}, "macro.dbt.get_incremental_delete_insert_sql": {"name": "get_incremental_delete_insert_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_delete_insert_sql", "macro_sql": "{% macro get_incremental_delete_insert_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_delete_insert_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_incremental_delete_insert_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6026812, "supported_languages": null}, "macro.dbt.default__get_incremental_delete_insert_sql": {"name": "default__get_incremental_delete_insert_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_delete_insert_sql", "macro_sql": "{% macro default__get_incremental_delete_insert_sql(arg_dict) %}\n\n  {% do return(get_delete_insert_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"unique_key\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_delete_insert_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.602931, "supported_languages": null}, "macro.dbt.get_incremental_merge_sql": {"name": "get_incremental_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_merge_sql", "macro_sql": "{% macro get_incremental_merge_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_merge_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6030898, "supported_languages": null}, "macro.dbt.default__get_incremental_merge_sql": {"name": "default__get_incremental_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_merge_sql", "macro_sql": "{% macro default__get_incremental_merge_sql(arg_dict) %}\n\n  {% do return(get_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"unique_key\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6033401, "supported_languages": null}, "macro.dbt.get_incremental_insert_overwrite_sql": {"name": "get_incremental_insert_overwrite_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_insert_overwrite_sql", "macro_sql": "{% macro get_incremental_insert_overwrite_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_insert_overwrite_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_insert_overwrite_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.603498, "supported_languages": null}, "macro.dbt.default__get_incremental_insert_overwrite_sql": {"name": "default__get_incremental_insert_overwrite_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_insert_overwrite_sql", "macro_sql": "{% macro default__get_incremental_insert_overwrite_sql(arg_dict) %}\n\n  {% do return(get_insert_overwrite_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_insert_overwrite_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.603723, "supported_languages": null}, "macro.dbt.get_incremental_default_sql": {"name": "get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_default_sql", "macro_sql": "{% macro get_incremental_default_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_default_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_incremental_default_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6038861, "supported_languages": null}, "macro.dbt.default__get_incremental_default_sql": {"name": "default__get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_default_sql", "macro_sql": "{% macro default__get_incremental_default_sql(arg_dict) %}\n\n  {% do return(get_incremental_append_sql(arg_dict)) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_incremental_append_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.604013, "supported_languages": null}, "macro.dbt.get_insert_into_sql": {"name": "get_insert_into_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_insert_into_sql", "macro_sql": "{% macro get_insert_into_sql(target_relation, temp_relation, dest_columns) %}\n\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n\n    insert into {{ target_relation }} ({{ dest_cols_csv }})\n    (\n        select {{ dest_cols_csv }}\n        from {{ temp_relation }}\n    )\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.604246, "supported_languages": null}, "macro.dbt.materialization_incremental_default": {"name": "materialization_incremental_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/incremental.sql", "original_file_path": "macros/materializations/models/incremental/incremental.sql", "unique_id": "macro.dbt.materialization_incremental_default", "macro_sql": "{% materialization incremental, default -%}\n\n  -- relations\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') -%}\n  {%- set temp_relation = make_temp_relation(target_relation)-%}\n  {%- set intermediate_relation = make_intermediate_relation(target_relation)-%}\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n\n  -- configs\n  {%- set unique_key = config.get('unique_key') -%}\n  {%- set full_refresh_mode = (should_full_refresh()  or existing_relation.is_view) -%}\n  {%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%}\n\n  -- the temp_ and backup_ relations should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation. This has to happen before\n  -- BEGIN, in a separate transaction\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation)-%}\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n   -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set to_drop = [] %}\n\n  {% if existing_relation is none %}\n      {% set build_sql = get_create_table_as_sql(False, target_relation, sql) %}\n  {% elif full_refresh_mode %}\n      {% set build_sql = get_create_table_as_sql(False, intermediate_relation, sql) %}\n      {% set need_swap = true %}\n  {% else %}\n    {% do run_query(get_create_table_as_sql(True, temp_relation, sql)) %}\n    {% do adapter.expand_target_column_types(\n             from_relation=temp_relation,\n             to_relation=target_relation) %}\n    {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#}\n    {% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %}\n    {% if not dest_columns %}\n      {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %}\n    {% endif %}\n\n    {#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#}\n    {% set incremental_strategy = config.get('incremental_strategy') or 'default' %}\n    {% set incremental_predicates = config.get('predicates', none) or config.get('incremental_predicates', none) %}\n    {% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %}\n    {% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'incremental_predicates': incremental_predicates }) %}\n    {% set build_sql = strategy_sql_macro_func(strategy_arg_dict) %}\n\n  {% endif %}\n\n  {% call statement(\"main\") %}\n      {{ build_sql }}\n  {% endcall %}\n\n  {% if need_swap %}\n      {% do adapter.rename_relation(target_relation, backup_relation) %}\n      {% do adapter.rename_relation(intermediate_relation, target_relation) %}\n      {% do to_drop.append(backup_relation) %}\n  {% endif %}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if existing_relation is none or existing_relation.is_view or should_full_refresh() %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {% do adapter.commit() %}\n\n  {% for rel in to_drop %}\n      {% do adapter.drop_relation(rel) %}\n  {% endfor %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_temp_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.should_full_refresh", "macro.dbt.incremental_validate_on_schema_change", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.get_create_table_as_sql", "macro.dbt.run_query", "macro.dbt.process_schema_changes", "macro.dbt.statement", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6085372, "supported_languages": ["sql"]}, "macro.dbt.incremental_validate_on_schema_change": {"name": "incremental_validate_on_schema_change", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.incremental_validate_on_schema_change", "macro_sql": "{% macro incremental_validate_on_schema_change(on_schema_change, default='ignore') %}\n\n   {% if on_schema_change not in ['sync_all_columns', 'append_new_columns', 'fail', 'ignore'] %}\n\n     {% set log_message = 'Invalid value for on_schema_change (%s) specified. Setting default value of %s.' % (on_schema_change, default) %}\n     {% do log(log_message) %}\n\n     {{ return(default) }}\n\n   {% else %}\n\n     {{ return(on_schema_change) }}\n\n   {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.613145, "supported_languages": null}, "macro.dbt.check_for_schema_changes": {"name": "check_for_schema_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.check_for_schema_changes", "macro_sql": "{% macro check_for_schema_changes(source_relation, target_relation) %}\n\n  {% set schema_changed = False %}\n\n  {%- set source_columns = adapter.get_columns_in_relation(source_relation) -%}\n  {%- set target_columns = adapter.get_columns_in_relation(target_relation) -%}\n  {%- set source_not_in_target = diff_columns(source_columns, target_columns) -%}\n  {%- set target_not_in_source = diff_columns(target_columns, source_columns) -%}\n\n  {% set new_target_types = diff_column_data_types(source_columns, target_columns) %}\n\n  {% if source_not_in_target != [] %}\n    {% set schema_changed = True %}\n  {% elif target_not_in_source != [] or new_target_types != [] %}\n    {% set schema_changed = True %}\n  {% elif new_target_types != [] %}\n    {% set schema_changed = True %}\n  {% endif %}\n\n  {% set changes_dict = {\n    'schema_changed': schema_changed,\n    'source_not_in_target': source_not_in_target,\n    'target_not_in_source': target_not_in_source,\n    'source_columns': source_columns,\n    'target_columns': target_columns,\n    'new_target_types': new_target_types\n  } %}\n\n  {% set msg %}\n    In {{ target_relation }}:\n        Schema changed: {{ schema_changed }}\n        Source columns not in target: {{ source_not_in_target }}\n        Target columns not in source: {{ target_not_in_source }}\n        New column types: {{ new_target_types }}\n  {% endset %}\n\n  {% do log(msg) %}\n\n  {{ return(changes_dict) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.diff_columns", "macro.dbt.diff_column_data_types"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.614183, "supported_languages": null}, "macro.dbt.sync_column_schemas": {"name": "sync_column_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.sync_column_schemas", "macro_sql": "{% macro sync_column_schemas(on_schema_change, target_relation, schema_changes_dict) %}\n\n  {%- set add_to_target_arr = schema_changes_dict['source_not_in_target'] -%}\n\n  {%- if on_schema_change == 'append_new_columns'-%}\n     {%- if add_to_target_arr | length > 0 -%}\n       {%- do alter_relation_add_remove_columns(target_relation, add_to_target_arr, none) -%}\n     {%- endif -%}\n\n  {% elif on_schema_change == 'sync_all_columns' %}\n     {%- set remove_from_target_arr = schema_changes_dict['target_not_in_source'] -%}\n     {%- set new_target_types = schema_changes_dict['new_target_types'] -%}\n\n     {% if add_to_target_arr | length > 0 or remove_from_target_arr | length > 0 %}\n       {%- do alter_relation_add_remove_columns(target_relation, add_to_target_arr, remove_from_target_arr) -%}\n     {% endif %}\n\n     {% if new_target_types != [] %}\n       {% for ntt in new_target_types %}\n         {% set column_name = ntt['column_name'] %}\n         {% set new_type = ntt['new_type'] %}\n         {% do alter_column_type(target_relation, column_name, new_type) %}\n       {% endfor %}\n     {% endif %}\n\n  {% endif %}\n\n  {% set schema_change_message %}\n    In {{ target_relation }}:\n        Schema change approach: {{ on_schema_change }}\n        Columns added: {{ add_to_target_arr }}\n        Columns removed: {{ remove_from_target_arr }}\n        Data types changed: {{ new_target_types }}\n  {% endset %}\n\n  {% do log(schema_change_message) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.alter_relation_add_remove_columns", "macro.dbt.alter_column_type"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.615208, "supported_languages": null}, "macro.dbt.process_schema_changes": {"name": "process_schema_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.process_schema_changes", "macro_sql": "{% macro process_schema_changes(on_schema_change, source_relation, target_relation) %}\n\n    {% if on_schema_change == 'ignore' %}\n\n     {{ return({}) }}\n\n    {% else %}\n\n      {% set schema_changes_dict = check_for_schema_changes(source_relation, target_relation) %}\n\n      {% if schema_changes_dict['schema_changed'] %}\n\n        {% if on_schema_change == 'fail' %}\n\n          {% set fail_msg %}\n              The source and target schemas on this incremental model are out of sync!\n              They can be reconciled in several ways:\n                - set the `on_schema_change` config to either append_new_columns or sync_all_columns, depending on your situation.\n                - Re-run the incremental model with `full_refresh: True` to update the target schema.\n                - update the schema manually and re-run the process.\n\n              Additional troubleshooting context:\n                 Source columns not in target: {{ schema_changes_dict['source_not_in_target'] }}\n                 Target columns not in source: {{ schema_changes_dict['target_not_in_source'] }}\n                 New column types: {{ schema_changes_dict['new_target_types'] }}\n          {% endset %}\n\n          {% do exceptions.raise_compiler_error(fail_msg) %}\n\n        {# -- unless we ignore, run the sync operation per the config #}\n        {% else %}\n\n          {% do sync_column_schemas(on_schema_change, target_relation, schema_changes_dict) %}\n\n        {% endif %}\n\n      {% endif %}\n\n      {{ return(schema_changes_dict['source_columns']) }}\n\n    {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.check_for_schema_changes", "macro.dbt.sync_column_schemas"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.615935, "supported_languages": null}, "macro.dbt.materialization_table_default": {"name": "materialization_table_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table/table.sql", "original_file_path": "macros/materializations/models/table/table.sql", "unique_id": "macro.dbt.materialization_table_default", "macro_sql": "{% materialization table, default %}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') %}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_table_as_sql(False, intermediate_relation, sql) }}\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n      {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% do create_indexes(target_relation) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.get_create_table_as_sql", "macro.dbt.create_indexes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6181371, "supported_languages": ["sql"]}, "macro.dbt.get_create_table_as_sql": {"name": "get_create_table_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table/create_table_as.sql", "original_file_path": "macros/materializations/models/table/create_table_as.sql", "unique_id": "macro.dbt.get_create_table_as_sql", "macro_sql": "{% macro get_create_table_as_sql(temporary, relation, sql) -%}\n  {{ adapter.dispatch('get_create_table_as_sql', 'dbt')(temporary, relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_table_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.618577, "supported_languages": null}, "macro.dbt.default__get_create_table_as_sql": {"name": "default__get_create_table_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table/create_table_as.sql", "original_file_path": "macros/materializations/models/table/create_table_as.sql", "unique_id": "macro.dbt.default__get_create_table_as_sql", "macro_sql": "{% macro default__get_create_table_as_sql(temporary, relation, sql) -%}\n  {{ return(create_table_as(temporary, relation, sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.618732, "supported_languages": null}, "macro.dbt.create_table_as": {"name": "create_table_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table/create_table_as.sql", "original_file_path": "macros/materializations/models/table/create_table_as.sql", "unique_id": "macro.dbt.create_table_as", "macro_sql": "{% macro create_table_as(temporary, relation, compiled_code, language='sql') -%}\n  {# backward compatibility for create_table_as that does not support language #}\n  {% if language == \"sql\" %}\n    {{ adapter.dispatch('create_table_as', 'dbt')(temporary, relation, compiled_code)}}\n  {% else %}\n    {{ adapter.dispatch('create_table_as', 'dbt')(temporary, relation, compiled_code, language) }}\n  {% endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.619096, "supported_languages": null}, "macro.dbt.default__create_table_as": {"name": "default__create_table_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table/create_table_as.sql", "original_file_path": "macros/materializations/models/table/create_table_as.sql", "unique_id": "macro.dbt.default__create_table_as", "macro_sql": "{% macro default__create_table_as(temporary, relation, sql) -%}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n\n  create {% if temporary: -%}temporary{%- endif %} table\n    {{ relation.include(database=(not temporary), schema=(not temporary)) }}\n  as (\n    {{ sql }}\n  );\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.61945, "supported_languages": null}, "macro.dbt.materialization_view_default": {"name": "materialization_view_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/view.sql", "original_file_path": "macros/materializations/models/view/view.sql", "unique_id": "macro.dbt.materialization_view_default", "macro_sql": "{%- materialization view, default -%}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='view') -%}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n     This relation (probably) doesn't exist yet. If it does exist, it's a leftover from\n     a previous run, and we're going to try to drop it immediately. At the end of this\n     materialization, we're going to rename the \"existing_relation\" to this identifier,\n     and then we're going to drop it. In order to make sure we run the correct one of:\n       - drop view ...\n       - drop table ...\n\n     We need to set the type of this relation to be the type of the existing_relation, if it exists,\n     or else \"view\" as a sane default if it does not. Note that if the existing_relation does not\n     exist, then there is nothing to move out of the way and subsequentally drop. In that case,\n     this relation will be effectively unused.\n  */\n  {%- set backup_relation_type = 'view' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_view_as_sql(intermediate_relation, sql) }}\n  {%- endcall %}\n\n  -- cleanup\n  -- move the existing view out of the way\n  {% if existing_relation is not none %}\n    {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {{ adapter.commit() }}\n\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization -%}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.run_hooks", "macro.dbt.drop_relation_if_exists", "macro.dbt.statement", "macro.dbt.get_create_view_as_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.62165, "supported_languages": ["sql"]}, "macro.dbt.handle_existing_table": {"name": "handle_existing_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/helpers.sql", "original_file_path": "macros/materializations/models/view/helpers.sql", "unique_id": "macro.dbt.handle_existing_table", "macro_sql": "{% macro handle_existing_table(full_refresh, old_relation) %}\n    {{ adapter.dispatch('handle_existing_table', 'dbt')(full_refresh, old_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__handle_existing_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.621908, "supported_languages": null}, "macro.dbt.default__handle_existing_table": {"name": "default__handle_existing_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/helpers.sql", "original_file_path": "macros/materializations/models/view/helpers.sql", "unique_id": "macro.dbt.default__handle_existing_table", "macro_sql": "{% macro default__handle_existing_table(full_refresh, old_relation) %}\n    {{ log(\"Dropping relation \" ~ old_relation ~ \" because it is of type \" ~ old_relation.type) }}\n    {{ adapter.drop_relation(old_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6220968, "supported_languages": null}, "macro.dbt.create_or_replace_view": {"name": "create_or_replace_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/create_or_replace_view.sql", "original_file_path": "macros/materializations/models/view/create_or_replace_view.sql", "unique_id": "macro.dbt.create_or_replace_view", "macro_sql": "{% macro create_or_replace_view() %}\n  {%- set identifier = model['alias'] -%}\n\n  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}\n  {%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}\n\n  {%- set target_relation = api.Relation.create(\n      identifier=identifier, schema=schema, database=database,\n      type='view') -%}\n  {% set grant_config = config.get('grants') %}\n\n  {{ run_hooks(pre_hooks) }}\n\n  -- If there's a table with the same name and we weren't told to full refresh,\n  -- that's an error. If we were told to full refresh, drop it. This behavior differs\n  -- for Snowflake and BigQuery, so multiple dispatch is used.\n  {%- if old_relation is not none and old_relation.is_table -%}\n    {{ handle_existing_table(should_full_refresh(), old_relation) }}\n  {%- endif -%}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_view_as_sql(target_relation, sql) }}\n  {%- endcall %}\n\n  {% set should_revoke = should_revoke(exists_as_view, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=True) %}\n\n  {{ run_hooks(post_hooks) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_hooks", "macro.dbt.handle_existing_table", "macro.dbt.should_full_refresh", "macro.dbt.statement", "macro.dbt.get_create_view_as_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.623378, "supported_languages": null}, "macro.dbt.get_create_view_as_sql": {"name": "get_create_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/create_view_as.sql", "original_file_path": "macros/materializations/models/view/create_view_as.sql", "unique_id": "macro.dbt.get_create_view_as_sql", "macro_sql": "{% macro get_create_view_as_sql(relation, sql) -%}\n  {{ adapter.dispatch('get_create_view_as_sql', 'dbt')(relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.623689, "supported_languages": null}, "macro.dbt.default__get_create_view_as_sql": {"name": "default__get_create_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/create_view_as.sql", "original_file_path": "macros/materializations/models/view/create_view_as.sql", "unique_id": "macro.dbt.default__get_create_view_as_sql", "macro_sql": "{% macro default__get_create_view_as_sql(relation, sql) -%}\n  {{ return(create_view_as(relation, sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_view_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.623824, "supported_languages": null}, "macro.dbt.create_view_as": {"name": "create_view_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/create_view_as.sql", "original_file_path": "macros/materializations/models/view/create_view_as.sql", "unique_id": "macro.dbt.create_view_as", "macro_sql": "{% macro create_view_as(relation, sql) -%}\n  {{ adapter.dispatch('create_view_as', 'dbt')(relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_view_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.623976, "supported_languages": null}, "macro.dbt.default__create_view_as": {"name": "default__create_view_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view/create_view_as.sql", "original_file_path": "macros/materializations/models/view/create_view_as.sql", "unique_id": "macro.dbt.default__create_view_as", "macro_sql": "{% macro default__create_view_as(relation, sql) -%}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n  create view {{ relation }} as (\n    {{ sql }}\n  );\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.624196, "supported_languages": null}, "macro.dbt.materialization_seed_default": {"name": "materialization_seed_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/seed.sql", "original_file_path": "macros/materializations/seeds/seed.sql", "unique_id": "macro.dbt.materialization_seed_default", "macro_sql": "{% materialization seed, default %}\n\n  {%- set identifier = model['alias'] -%}\n  {%- set full_refresh_mode = (should_full_refresh()) -%}\n\n  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}\n\n  {%- set exists_as_table = (old_relation is not none and old_relation.is_table) -%}\n  {%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}\n\n  {%- set grant_config = config.get('grants') -%}\n  {%- set agate_table = load_agate_table() -%}\n  -- grab current tables grants config for comparision later on\n\n  {%- do store_result('agate_table', response='OK', agate_table=agate_table) -%}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% set create_table_sql = \"\" %}\n  {% if exists_as_view %}\n    {{ exceptions.raise_compiler_error(\"Cannot seed to '{}', it is a view\".format(old_relation)) }}\n  {% elif exists_as_table %}\n    {% set create_table_sql = reset_csv_table(model, full_refresh_mode, old_relation, agate_table) %}\n  {% else %}\n    {% set create_table_sql = create_csv_table(model, agate_table) %}\n  {% endif %}\n\n  {% set code = 'CREATE' if full_refresh_mode else 'INSERT' %}\n  {% set rows_affected = (agate_table.rows | length) %}\n  {% set sql = load_csv_rows(model, agate_table) %}\n\n  {% call noop_statement('main', code ~ ' ' ~ rows_affected, code, rows_affected) %}\n    {{ get_csv_sql(create_table_sql, sql) }};\n  {% endcall %}\n\n  {% set target_relation = this.incorporate(type='table') %}\n\n  {% set should_revoke = should_revoke(old_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if full_refresh_mode or not exists_as_table %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.should_full_refresh", "macro.dbt.run_hooks", "macro.dbt.reset_csv_table", "macro.dbt.create_csv_table", "macro.dbt.load_csv_rows", "macro.dbt.noop_statement", "macro.dbt.get_csv_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.627002, "supported_languages": ["sql"]}, "macro.dbt.create_csv_table": {"name": "create_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.create_csv_table", "macro_sql": "{% macro create_csv_table(model, agate_table) -%}\n  {{ adapter.dispatch('create_csv_table', 'dbt')(model, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.631079, "supported_languages": null}, "macro.dbt.default__create_csv_table": {"name": "default__create_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__create_csv_table", "macro_sql": "{% macro default__create_csv_table(model, agate_table) %}\n  {%- set column_override = model['config'].get('column_types', {}) -%}\n  {%- set quote_seed_column = model['config'].get('quote_columns', None) -%}\n\n  {% set sql %}\n    create table {{ this.render() }} (\n        {%- for col_name in agate_table.column_names -%}\n            {%- set inferred_type = adapter.convert_type(agate_table, loop.index0) -%}\n            {%- set type = column_override.get(col_name, inferred_type) -%}\n            {%- set column_name = (col_name | string) -%}\n            {{ adapter.quote_seed_column(column_name, quote_seed_column) }} {{ type }} {%- if not loop.last -%}, {%- endif -%}\n        {%- endfor -%}\n    )\n  {% endset %}\n\n  {% call statement('_') -%}\n    {{ sql }}\n  {%- endcall %}\n\n  {{ return(sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.63184, "supported_languages": null}, "macro.dbt.reset_csv_table": {"name": "reset_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.reset_csv_table", "macro_sql": "{% macro reset_csv_table(model, full_refresh, old_relation, agate_table) -%}\n  {{ adapter.dispatch('reset_csv_table', 'dbt')(model, full_refresh, old_relation, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__reset_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.632041, "supported_languages": null}, "macro.dbt.default__reset_csv_table": {"name": "default__reset_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__reset_csv_table", "macro_sql": "{% macro default__reset_csv_table(model, full_refresh, old_relation, agate_table) %}\n    {% set sql = \"\" %}\n    {% if full_refresh %}\n        {{ adapter.drop_relation(old_relation) }}\n        {% set sql = create_csv_table(model, agate_table) %}\n    {% else %}\n        {{ adapter.truncate_relation(old_relation) }}\n        {% set sql = \"truncate table \" ~ old_relation %}\n    {% endif %}\n\n    {{ return(sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.632442, "supported_languages": null}, "macro.dbt.get_csv_sql": {"name": "get_csv_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_csv_sql", "macro_sql": "{% macro get_csv_sql(create_or_truncate_sql, insert_sql) %}\n    {{ adapter.dispatch('get_csv_sql', 'dbt')(create_or_truncate_sql, insert_sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_csv_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.632604, "supported_languages": null}, "macro.dbt.default__get_csv_sql": {"name": "default__get_csv_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_csv_sql", "macro_sql": "{% macro default__get_csv_sql(create_or_truncate_sql, insert_sql) %}\n    {{ create_or_truncate_sql }};\n    -- dbt seed --\n    {{ insert_sql }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.632715, "supported_languages": null}, "macro.dbt.get_binding_char": {"name": "get_binding_char", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_binding_char", "macro_sql": "{% macro get_binding_char() -%}\n  {{ adapter.dispatch('get_binding_char', 'dbt')() }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6328309, "supported_languages": null}, "macro.dbt.default__get_binding_char": {"name": "default__get_binding_char", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_binding_char", "macro_sql": "{% macro default__get_binding_char() %}\n  {{ return('%s') }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.632926, "supported_languages": null}, "macro.dbt.get_batch_size": {"name": "get_batch_size", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_batch_size", "macro_sql": "{% macro get_batch_size() -%}\n  {{ return(adapter.dispatch('get_batch_size', 'dbt')()) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_batch_size"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.633058, "supported_languages": null}, "macro.dbt.default__get_batch_size": {"name": "default__get_batch_size", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_batch_size", "macro_sql": "{% macro default__get_batch_size() %}\n  {{ return(10000) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.633155, "supported_languages": null}, "macro.dbt.get_seed_column_quoted_csv": {"name": "get_seed_column_quoted_csv", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_seed_column_quoted_csv", "macro_sql": "{% macro get_seed_column_quoted_csv(model, column_names) %}\n  {%- set quote_seed_column = model['config'].get('quote_columns', None) -%}\n    {% set quoted = [] %}\n    {% for col in column_names -%}\n        {%- do quoted.append(adapter.quote_seed_column(col, quote_seed_column)) -%}\n    {%- endfor %}\n\n    {%- set dest_cols_csv = quoted | join(', ') -%}\n    {{ return(dest_cols_csv) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.633557, "supported_languages": null}, "macro.dbt.load_csv_rows": {"name": "load_csv_rows", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.load_csv_rows", "macro_sql": "{% macro load_csv_rows(model, agate_table) -%}\n  {{ adapter.dispatch('load_csv_rows', 'dbt')(model, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__load_csv_rows"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6337159, "supported_languages": null}, "macro.dbt.default__load_csv_rows": {"name": "default__load_csv_rows", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__load_csv_rows", "macro_sql": "{% macro default__load_csv_rows(model, agate_table) %}\n\n  {% set batch_size = get_batch_size() %}\n\n  {% set cols_sql = get_seed_column_quoted_csv(model, agate_table.column_names) %}\n  {% set bindings = [] %}\n\n  {% set statements = [] %}\n\n  {% for chunk in agate_table.rows | batch(batch_size) %}\n      {% set bindings = [] %}\n\n      {% for row in chunk %}\n          {% do bindings.extend(row) %}\n      {% endfor %}\n\n      {% set sql %}\n          insert into {{ this.render() }} ({{ cols_sql }}) values\n          {% for row in chunk -%}\n              ({%- for column in agate_table.column_names -%}\n                  {{ get_binding_char() }}\n                  {%- if not loop.last%},{%- endif %}\n              {%- endfor -%})\n              {%- if not loop.last%},{%- endif %}\n          {%- endfor %}\n      {% endset %}\n\n      {% do adapter.add_query(sql, bindings=bindings, abridge_sql_log=True) %}\n\n      {% if loop.index0 == 0 %}\n          {% do statements.append(sql) %}\n      {% endif %}\n  {% endfor %}\n\n  {# Return SQL so we can render it out into the compiled files #}\n  {{ return(statements[0]) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_batch_size", "macro.dbt.get_seed_column_quoted_csv", "macro.dbt.get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.634801, "supported_languages": null}, "macro.dbt.generate_alias_name": {"name": "generate_alias_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_alias.sql", "original_file_path": "macros/get_custom_name/get_custom_alias.sql", "unique_id": "macro.dbt.generate_alias_name", "macro_sql": "{% macro generate_alias_name(custom_alias_name=none, node=none) -%}\n    {% do return(adapter.dispatch('generate_alias_name', 'dbt')(custom_alias_name, node)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_alias_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.635134, "supported_languages": null}, "macro.dbt.default__generate_alias_name": {"name": "default__generate_alias_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_alias.sql", "original_file_path": "macros/get_custom_name/get_custom_alias.sql", "unique_id": "macro.dbt.default__generate_alias_name", "macro_sql": "{% macro default__generate_alias_name(custom_alias_name=none, node=none) -%}\n\n    {%- if custom_alias_name is none -%}\n\n        {{ node.name }}\n\n    {%- else -%}\n\n        {{ custom_alias_name | trim }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6353269, "supported_languages": null}, "macro.dbt.generate_schema_name": {"name": "generate_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.generate_schema_name", "macro_sql": "{% macro generate_schema_name(custom_schema_name=none, node=none) -%}\n    {{ return(adapter.dispatch('generate_schema_name', 'dbt')(custom_schema_name, node)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_schema_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.635782, "supported_languages": null}, "macro.dbt.default__generate_schema_name": {"name": "default__generate_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.default__generate_schema_name", "macro_sql": "{% macro default__generate_schema_name(custom_schema_name, node) -%}\n\n    {%- set default_schema = target.schema -%}\n    {%- if custom_schema_name is none -%}\n\n        {{ default_schema }}\n\n    {%- else -%}\n\n        {{ default_schema }}_{{ custom_schema_name | trim }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.636002, "supported_languages": null}, "macro.dbt.generate_schema_name_for_env": {"name": "generate_schema_name_for_env", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.generate_schema_name_for_env", "macro_sql": "{% macro generate_schema_name_for_env(custom_schema_name, node) -%}\n\n    {%- set default_schema = target.schema -%}\n    {%- if target.name == 'prod' and custom_schema_name is not none -%}\n\n        {{ custom_schema_name | trim }}\n\n    {%- else -%}\n\n        {{ default_schema }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.636239, "supported_languages": null}, "macro.dbt.generate_database_name": {"name": "generate_database_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_database.sql", "original_file_path": "macros/get_custom_name/get_custom_database.sql", "unique_id": "macro.dbt.generate_database_name", "macro_sql": "{% macro generate_database_name(custom_database_name=none, node=none) -%}\n    {% do return(adapter.dispatch('generate_database_name', 'dbt')(custom_database_name, node)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_database_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.636579, "supported_languages": null}, "macro.dbt.default__generate_database_name": {"name": "default__generate_database_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_database.sql", "original_file_path": "macros/get_custom_name/get_custom_database.sql", "unique_id": "macro.dbt.default__generate_database_name", "macro_sql": "{% macro default__generate_database_name(custom_database_name=none, node=none) -%}\n    {%- set default_database = target.database -%}\n    {%- if custom_database_name is none -%}\n\n        {{ default_database }}\n\n    {%- else -%}\n\n        {{ custom_database_name }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.636798, "supported_languages": null}, "macro.dbt.default__test_relationships": {"name": "default__test_relationships", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/relationships.sql", "original_file_path": "macros/generic_test_sql/relationships.sql", "unique_id": "macro.dbt.default__test_relationships", "macro_sql": "{% macro default__test_relationships(model, column_name, to, field) %}\n\nwith child as (\n    select {{ column_name }} as from_field\n    from {{ model }}\n    where {{ column_name }} is not null\n),\n\nparent as (\n    select {{ field }} as to_field\n    from {{ to }}\n)\n\nselect\n    from_field\n\nfrom child\nleft join parent\n    on child.from_field = parent.to_field\n\nwhere parent.to_field is null\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6371, "supported_languages": null}, "macro.dbt.default__test_not_null": {"name": "default__test_not_null", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/not_null.sql", "original_file_path": "macros/generic_test_sql/not_null.sql", "unique_id": "macro.dbt.default__test_not_null", "macro_sql": "{% macro default__test_not_null(model, column_name) %}\n\n{% set column_list = '*' if should_store_failures() else column_name %}\n\nselect {{ column_list }}\nfrom {{ model }}\nwhere {{ column_name }} is null\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.should_store_failures"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.637353, "supported_languages": null}, "macro.dbt.default__test_unique": {"name": "default__test_unique", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/unique.sql", "original_file_path": "macros/generic_test_sql/unique.sql", "unique_id": "macro.dbt.default__test_unique", "macro_sql": "{% macro default__test_unique(model, column_name) %}\n\nselect\n    {{ column_name }} as unique_field,\n    count(*) as n_records\n\nfrom {{ model }}\nwhere {{ column_name }} is not null\ngroup by {{ column_name }}\nhaving count(*) > 1\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.637565, "supported_languages": null}, "macro.dbt.default__test_accepted_values": {"name": "default__test_accepted_values", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/accepted_values.sql", "original_file_path": "macros/generic_test_sql/accepted_values.sql", "unique_id": "macro.dbt.default__test_accepted_values", "macro_sql": "{% macro default__test_accepted_values(model, column_name, values, quote=True) %}\n\nwith all_values as (\n\n    select\n        {{ column_name }} as value_field,\n        count(*) as n_records\n\n    from {{ model }}\n    group by {{ column_name }}\n\n)\n\nselect *\nfrom all_values\nwhere value_field not in (\n    {% for value in values -%}\n        {% if quote -%}\n        '{{ value }}'\n        {%- else -%}\n        {{ value }}\n        {%- endif -%}\n        {%- if not loop.last -%},{%- endif %}\n    {%- endfor %}\n)\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6380422, "supported_languages": null}, "macro.dbt.statement": {"name": "statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.statement", "macro_sql": "\n{%- macro statement(name=None, fetch_result=False, auto_begin=True, language='sql') -%}\n  {%- if execute: -%}\n    {%- set compiled_code = caller() -%}\n\n    {%- if name == 'main' -%}\n      {{ log('Writing runtime {} for node \"{}\"'.format(language, model['unique_id'])) }}\n      {{ write(compiled_code) }}\n    {%- endif -%}\n    {%- if language == 'sql'-%}\n      {%- set res, table = adapter.execute(compiled_code, auto_begin=auto_begin, fetch=fetch_result) -%}\n    {%- elif language == 'python' -%}\n      {%- set res = submit_python_job(model, compiled_code) -%}\n      {#-- TODO: What should table be for python models? --#}\n      {%- set table = None -%}\n    {%- else -%}\n      {% do exceptions.raise_compiler_error(\"statement macro didn't get supported language\") %}\n    {%- endif -%}\n\n    {%- if name is not none -%}\n      {{ store_result(name, response=res, agate_table=table) }}\n    {%- endif -%}\n\n  {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.639293, "supported_languages": null}, "macro.dbt.noop_statement": {"name": "noop_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.noop_statement", "macro_sql": "{% macro noop_statement(name=None, message=None, code=None, rows_affected=None, res=None) -%}\n  {%- set sql = caller() -%}\n\n  {%- if name == 'main' -%}\n    {{ log('Writing runtime SQL for node \"{}\"'.format(model['unique_id'])) }}\n    {{ write(sql) }}\n  {%- endif -%}\n\n  {%- if name is not none -%}\n    {{ store_raw_result(name, message=message, code=code, rows_affected=rows_affected, agate_table=res) }}\n  {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6397882, "supported_languages": null}, "macro.dbt.run_query": {"name": "run_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.run_query", "macro_sql": "{% macro run_query(sql) %}\n  {% call statement(\"run_query_statement\", fetch_result=true, auto_begin=false) %}\n    {{ sql }}\n  {% endcall %}\n\n  {% do return(load_result(\"run_query_statement\").table) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.640039, "supported_languages": null}, "macro.dbt.convert_datetime": {"name": "convert_datetime", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.convert_datetime", "macro_sql": "{% macro convert_datetime(date_str, date_fmt) %}\n\n  {% set error_msg -%}\n      The provided partition date '{{ date_str }}' does not match the expected format '{{ date_fmt }}'\n  {%- endset %}\n\n  {% set res = try_or_compiler_error(error_msg, modules.datetime.datetime.strptime, date_str.strip(), date_fmt) %}\n  {{ return(res) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.641572, "supported_languages": null}, "macro.dbt.dates_in_range": {"name": "dates_in_range", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.dates_in_range", "macro_sql": "{% macro dates_in_range(start_date_str, end_date_str=none, in_fmt=\"%Y%m%d\", out_fmt=\"%Y%m%d\") %}\n    {% set end_date_str = start_date_str if end_date_str is none else end_date_str %}\n\n    {% set start_date = convert_datetime(start_date_str, in_fmt) %}\n    {% set end_date = convert_datetime(end_date_str, in_fmt) %}\n\n    {% set day_count = (end_date - start_date).days %}\n    {% if day_count < 0 %}\n        {% set msg -%}\n            Partiton start date is after the end date ({{ start_date }}, {{ end_date }})\n        {%- endset %}\n\n        {{ exceptions.raise_compiler_error(msg, model) }}\n    {% endif %}\n\n    {% set date_list = [] %}\n    {% for i in range(0, day_count + 1) %}\n        {% set the_date = (modules.datetime.timedelta(days=i) + start_date) %}\n        {% if not out_fmt %}\n            {% set _ = date_list.append(the_date) %}\n        {% else %}\n            {% set _ = date_list.append(the_date.strftime(out_fmt)) %}\n        {% endif %}\n    {% endfor %}\n\n    {{ return(date_list) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.convert_datetime"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.642743, "supported_languages": null}, "macro.dbt.partition_range": {"name": "partition_range", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.partition_range", "macro_sql": "{% macro partition_range(raw_partition_date, date_fmt='%Y%m%d') %}\n    {% set partition_range = (raw_partition_date | string).split(\",\") %}\n\n    {% if (partition_range | length) == 1 %}\n      {% set start_date = partition_range[0] %}\n      {% set end_date = none %}\n    {% elif (partition_range | length) == 2 %}\n      {% set start_date = partition_range[0] %}\n      {% set end_date = partition_range[1] %}\n    {% else %}\n      {{ exceptions.raise_compiler_error(\"Invalid partition time. Expected format: {Start Date}[,{End Date}]. Got: \" ~ raw_partition_date) }}\n    {% endif %}\n\n    {{ return(dates_in_range(start_date, end_date, in_fmt=date_fmt)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.dates_in_range"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6433878, "supported_languages": null}, "macro.dbt.py_current_timestring": {"name": "py_current_timestring", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.py_current_timestring", "macro_sql": "{% macro py_current_timestring() %}\n    {% set dt = modules.datetime.datetime.now() %}\n    {% do return(dt.strftime(\"%Y%m%d%H%M%S%f\")) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6435862, "supported_languages": null}, "macro.dbt.except": {"name": "except", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/except.sql", "original_file_path": "macros/utils/except.sql", "unique_id": "macro.dbt.except", "macro_sql": "{% macro except() %}\n  {{ return(adapter.dispatch('except', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__except"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6437812, "supported_languages": null}, "macro.dbt.default__except": {"name": "default__except", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/except.sql", "original_file_path": "macros/utils/except.sql", "unique_id": "macro.dbt.default__except", "macro_sql": "{% macro default__except() %}\n\n    except\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.643842, "supported_languages": null}, "macro.dbt.replace": {"name": "replace", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/replace.sql", "original_file_path": "macros/utils/replace.sql", "unique_id": "macro.dbt.replace", "macro_sql": "{% macro replace(field, old_chars, new_chars) -%}\n    {{ return(adapter.dispatch('replace', 'dbt') (field, old_chars, new_chars)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__replace"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6441212, "supported_languages": null}, "macro.dbt.default__replace": {"name": "default__replace", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/replace.sql", "original_file_path": "macros/utils/replace.sql", "unique_id": "macro.dbt.default__replace", "macro_sql": "{% macro default__replace(field, old_chars, new_chars) %}\n\n    replace(\n        {{ field }},\n        {{ old_chars }},\n        {{ new_chars }}\n    )\n\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.644257, "supported_languages": null}, "macro.dbt.concat": {"name": "concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/concat.sql", "original_file_path": "macros/utils/concat.sql", "unique_id": "macro.dbt.concat", "macro_sql": "{% macro concat(fields) -%}\n  {{ return(adapter.dispatch('concat', 'dbt')(fields)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__concat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.644465, "supported_languages": null}, "macro.dbt.default__concat": {"name": "default__concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/concat.sql", "original_file_path": "macros/utils/concat.sql", "unique_id": "macro.dbt.default__concat", "macro_sql": "{% macro default__concat(fields) -%}\n    {{ fields|join(' || ') }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.64457, "supported_languages": null}, "macro.dbt.length": {"name": "length", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/length.sql", "original_file_path": "macros/utils/length.sql", "unique_id": "macro.dbt.length", "macro_sql": "{% macro length(expression) -%}\n    {{ return(adapter.dispatch('length', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__length"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.644785, "supported_languages": null}, "macro.dbt.default__length": {"name": "default__length", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/length.sql", "original_file_path": "macros/utils/length.sql", "unique_id": "macro.dbt.default__length", "macro_sql": "{% macro default__length(expression) %}\n\n    length(\n        {{ expression }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.644872, "supported_languages": null}, "macro.dbt.dateadd": {"name": "dateadd", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt.dateadd", "macro_sql": "{% macro dateadd(datepart, interval, from_date_or_timestamp) %}\n  {{ return(adapter.dispatch('dateadd', 'dbt')(datepart, interval, from_date_or_timestamp)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__dateadd"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6451578, "supported_languages": null}, "macro.dbt.default__dateadd": {"name": "default__dateadd", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt.default__dateadd", "macro_sql": "{% macro default__dateadd(datepart, interval, from_date_or_timestamp) %}\n\n    dateadd(\n        {{ datepart }},\n        {{ interval }},\n        {{ from_date_or_timestamp }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.645298, "supported_languages": null}, "macro.dbt.intersect": {"name": "intersect", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/intersect.sql", "original_file_path": "macros/utils/intersect.sql", "unique_id": "macro.dbt.intersect", "macro_sql": "{% macro intersect() %}\n  {{ return(adapter.dispatch('intersect', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__intersect"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.64549, "supported_languages": null}, "macro.dbt.default__intersect": {"name": "default__intersect", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/intersect.sql", "original_file_path": "macros/utils/intersect.sql", "unique_id": "macro.dbt.default__intersect", "macro_sql": "{% macro default__intersect() %}\n\n    intersect\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6455529, "supported_languages": null}, "macro.dbt.escape_single_quotes": {"name": "escape_single_quotes", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/escape_single_quotes.sql", "original_file_path": "macros/utils/escape_single_quotes.sql", "unique_id": "macro.dbt.escape_single_quotes", "macro_sql": "{% macro escape_single_quotes(expression) %}\n      {{ return(adapter.dispatch('escape_single_quotes', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__escape_single_quotes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.64578, "supported_languages": null}, "macro.dbt.default__escape_single_quotes": {"name": "default__escape_single_quotes", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/escape_single_quotes.sql", "original_file_path": "macros/utils/escape_single_quotes.sql", "unique_id": "macro.dbt.default__escape_single_quotes", "macro_sql": "{% macro default__escape_single_quotes(expression) -%}\n{{ expression | replace(\"'\",\"''\") }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.645895, "supported_languages": null}, "macro.dbt.right": {"name": "right", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/right.sql", "original_file_path": "macros/utils/right.sql", "unique_id": "macro.dbt.right", "macro_sql": "{% macro right(string_text, length_expression) -%}\n    {{ return(adapter.dispatch('right', 'dbt') (string_text, length_expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__right"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.646142, "supported_languages": null}, "macro.dbt.default__right": {"name": "default__right", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/right.sql", "original_file_path": "macros/utils/right.sql", "unique_id": "macro.dbt.default__right", "macro_sql": "{% macro default__right(string_text, length_expression) %}\n\n    right(\n        {{ string_text }},\n        {{ length_expression }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.646257, "supported_languages": null}, "macro.dbt.listagg": {"name": "listagg", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt.listagg", "macro_sql": "{% macro listagg(measure, delimiter_text=\"','\", order_by_clause=none, limit_num=none) -%}\n    {{ return(adapter.dispatch('listagg', 'dbt') (measure, delimiter_text, order_by_clause, limit_num)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__listagg"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.646784, "supported_languages": null}, "macro.dbt.default__listagg": {"name": "default__listagg", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt.default__listagg", "macro_sql": "{% macro default__listagg(measure, delimiter_text, order_by_clause, limit_num) -%}\n\n    {% if limit_num -%}\n    array_to_string(\n        array_slice(\n            array_agg(\n                {{ measure }}\n            ){% if order_by_clause -%}\n            within group ({{ order_by_clause }})\n            {%- endif %}\n            ,0\n            ,{{ limit_num }}\n        ),\n        {{ delimiter_text }}\n        )\n    {%- else %}\n    listagg(\n        {{ measure }},\n        {{ delimiter_text }}\n        )\n        {% if order_by_clause -%}\n        within group ({{ order_by_clause }})\n        {%- endif %}\n    {%- endif %}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6681972, "supported_languages": null}, "macro.dbt.datediff": {"name": "datediff", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt.datediff", "macro_sql": "{% macro datediff(first_date, second_date, datepart) %}\n  {{ return(adapter.dispatch('datediff', 'dbt')(first_date, second_date, datepart)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__datediff"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.668546, "supported_languages": null}, "macro.dbt.default__datediff": {"name": "default__datediff", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt.default__datediff", "macro_sql": "{% macro default__datediff(first_date, second_date, datepart) -%}\n\n    datediff(\n        {{ datepart }},\n        {{ first_date }},\n        {{ second_date }}\n        )\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.668691, "supported_languages": null}, "macro.dbt.safe_cast": {"name": "safe_cast", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/safe_cast.sql", "original_file_path": "macros/utils/safe_cast.sql", "unique_id": "macro.dbt.safe_cast", "macro_sql": "{% macro safe_cast(field, type) %}\n  {{ return(adapter.dispatch('safe_cast', 'dbt') (field, type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__safe_cast"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.668951, "supported_languages": null}, "macro.dbt.default__safe_cast": {"name": "default__safe_cast", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/safe_cast.sql", "original_file_path": "macros/utils/safe_cast.sql", "unique_id": "macro.dbt.default__safe_cast", "macro_sql": "{% macro default__safe_cast(field, type) %}\n    {# most databases don't support this function yet\n    so we just need to use cast #}\n    cast({{field}} as {{type}})\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6690712, "supported_languages": null}, "macro.dbt.hash": {"name": "hash", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/hash.sql", "original_file_path": "macros/utils/hash.sql", "unique_id": "macro.dbt.hash", "macro_sql": "{% macro hash(field) -%}\n  {{ return(adapter.dispatch('hash', 'dbt') (field)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__hash"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.669299, "supported_languages": null}, "macro.dbt.default__hash": {"name": "default__hash", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/hash.sql", "original_file_path": "macros/utils/hash.sql", "unique_id": "macro.dbt.default__hash", "macro_sql": "{% macro default__hash(field) -%}\n    md5(cast({{ field }} as {{ api.Column.translate_type('string') }}))\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.669434, "supported_languages": null}, "macro.dbt.cast_bool_to_text": {"name": "cast_bool_to_text", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/cast_bool_to_text.sql", "original_file_path": "macros/utils/cast_bool_to_text.sql", "unique_id": "macro.dbt.cast_bool_to_text", "macro_sql": "{% macro cast_bool_to_text(field) %}\n  {{ adapter.dispatch('cast_bool_to_text', 'dbt') (field) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__cast_bool_to_text"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6696472, "supported_languages": null}, "macro.dbt.default__cast_bool_to_text": {"name": "default__cast_bool_to_text", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/cast_bool_to_text.sql", "original_file_path": "macros/utils/cast_bool_to_text.sql", "unique_id": "macro.dbt.default__cast_bool_to_text", "macro_sql": "{% macro default__cast_bool_to_text(field) %}\n    cast({{ field }} as {{ api.Column.translate_type('string') }})\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.669782, "supported_languages": null}, "macro.dbt.any_value": {"name": "any_value", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt.any_value", "macro_sql": "{% macro any_value(expression) -%}\n    {{ return(adapter.dispatch('any_value', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__any_value"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.669991, "supported_languages": null}, "macro.dbt.default__any_value": {"name": "default__any_value", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt.default__any_value", "macro_sql": "{% macro default__any_value(expression) -%}\n\n    any_value({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.670079, "supported_languages": null}, "macro.dbt.position": {"name": "position", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/position.sql", "original_file_path": "macros/utils/position.sql", "unique_id": "macro.dbt.position", "macro_sql": "{% macro position(substring_text, string_text) -%}\n    {{ return(adapter.dispatch('position', 'dbt') (substring_text, string_text)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__position"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6703281, "supported_languages": null}, "macro.dbt.default__position": {"name": "default__position", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/position.sql", "original_file_path": "macros/utils/position.sql", "unique_id": "macro.dbt.default__position", "macro_sql": "{% macro default__position(substring_text, string_text) %}\n\n    position(\n        {{ substring_text }} in {{ string_text }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.670441, "supported_languages": null}, "macro.dbt.string_literal": {"name": "string_literal", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/literal.sql", "original_file_path": "macros/utils/literal.sql", "unique_id": "macro.dbt.string_literal", "macro_sql": "{%- macro string_literal(value) -%}\n  {{ return(adapter.dispatch('string_literal', 'dbt') (value)) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__string_literal"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.670652, "supported_languages": null}, "macro.dbt.default__string_literal": {"name": "default__string_literal", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/literal.sql", "original_file_path": "macros/utils/literal.sql", "unique_id": "macro.dbt.default__string_literal", "macro_sql": "{% macro default__string_literal(value) -%}\n    '{{ value }}'\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.670739, "supported_languages": null}, "macro.dbt.type_string": {"name": "type_string", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_string", "macro_sql": "\n\n{%- macro type_string() -%}\n  {{ return(adapter.dispatch('type_string', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_string"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.671568, "supported_languages": null}, "macro.dbt.default__type_string": {"name": "default__type_string", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_string", "macro_sql": "{% macro default__type_string() %}\n    {{ return(api.Column.translate_type(\"string\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6716979, "supported_languages": null}, "macro.dbt.type_timestamp": {"name": "type_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_timestamp", "macro_sql": "\n\n{%- macro type_timestamp() -%}\n  {{ return(adapter.dispatch('type_timestamp', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.671838, "supported_languages": null}, "macro.dbt.default__type_timestamp": {"name": "default__type_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_timestamp", "macro_sql": "{% macro default__type_timestamp() %}\n    {{ return(api.Column.translate_type(\"timestamp\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6720278, "supported_languages": null}, "macro.dbt.type_float": {"name": "type_float", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_float", "macro_sql": "\n\n{%- macro type_float() -%}\n  {{ return(adapter.dispatch('type_float', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_float"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6721652, "supported_languages": null}, "macro.dbt.default__type_float": {"name": "default__type_float", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_float", "macro_sql": "{% macro default__type_float() %}\n    {{ return(api.Column.translate_type(\"float\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672292, "supported_languages": null}, "macro.dbt.type_numeric": {"name": "type_numeric", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_numeric", "macro_sql": "\n\n{%- macro type_numeric() -%}\n  {{ return(adapter.dispatch('type_numeric', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_numeric"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672431, "supported_languages": null}, "macro.dbt.default__type_numeric": {"name": "default__type_numeric", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_numeric", "macro_sql": "{% macro default__type_numeric() %}\n    {{ return(api.Column.numeric_type(\"numeric\", 28, 6)) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672582, "supported_languages": null}, "macro.dbt.type_bigint": {"name": "type_bigint", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_bigint", "macro_sql": "\n\n{%- macro type_bigint() -%}\n  {{ return(adapter.dispatch('type_bigint', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_bigint"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672719, "supported_languages": null}, "macro.dbt.default__type_bigint": {"name": "default__type_bigint", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_bigint", "macro_sql": "{% macro default__type_bigint() %}\n    {{ return(api.Column.translate_type(\"bigint\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672846, "supported_languages": null}, "macro.dbt.type_int": {"name": "type_int", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_int", "macro_sql": "\n\n{%- macro type_int() -%}\n  {{ return(adapter.dispatch('type_int', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_int"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.672983, "supported_languages": null}, "macro.dbt.default__type_int": {"name": "default__type_int", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_int", "macro_sql": "{%- macro default__type_int() -%}\n  {{ return(api.Column.translate_type(\"integer\")) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673106, "supported_languages": null}, "macro.dbt.type_boolean": {"name": "type_boolean", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_boolean", "macro_sql": "\n\n{%- macro type_boolean() -%}\n  {{ return(adapter.dispatch('type_boolean', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_boolean"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673244, "supported_languages": null}, "macro.dbt.default__type_boolean": {"name": "default__type_boolean", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_boolean", "macro_sql": "{%- macro default__type_boolean() -%}\n  {{ return(api.Column.translate_type(\"boolean\")) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673367, "supported_languages": null}, "macro.dbt.array_concat": {"name": "array_concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_concat.sql", "original_file_path": "macros/utils/array_concat.sql", "unique_id": "macro.dbt.array_concat", "macro_sql": "{% macro array_concat(array_1, array_2) -%}\n  {{ return(adapter.dispatch('array_concat', 'dbt')(array_1, array_2)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_concat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673606, "supported_languages": null}, "macro.dbt.default__array_concat": {"name": "default__array_concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_concat.sql", "original_file_path": "macros/utils/array_concat.sql", "unique_id": "macro.dbt.default__array_concat", "macro_sql": "{% macro default__array_concat(array_1, array_2) -%}\n    array_cat({{ array_1 }}, {{ array_2 }})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673718, "supported_languages": null}, "macro.dbt.bool_or": {"name": "bool_or", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/bool_or.sql", "original_file_path": "macros/utils/bool_or.sql", "unique_id": "macro.dbt.bool_or", "macro_sql": "{% macro bool_or(expression) -%}\n    {{ return(adapter.dispatch('bool_or', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__bool_or"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.673928, "supported_languages": null}, "macro.dbt.default__bool_or": {"name": "default__bool_or", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/bool_or.sql", "original_file_path": "macros/utils/bool_or.sql", "unique_id": "macro.dbt.default__bool_or", "macro_sql": "{% macro default__bool_or(expression) -%}\n\n    bool_or({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.674016, "supported_languages": null}, "macro.dbt.last_day": {"name": "last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.last_day", "macro_sql": "{% macro last_day(date, datepart) %}\n  {{ return(adapter.dispatch('last_day', 'dbt') (date, datepart)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.674309, "supported_languages": null}, "macro.dbt.default_last_day": {"name": "default_last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.default_last_day", "macro_sql": "\n\n{%- macro default_last_day(date, datepart) -%}\n    cast(\n        {{dbt.dateadd('day', '-1',\n        dbt.dateadd(datepart, '1', dbt.date_trunc(datepart, date))\n        )}}\n        as date)\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.dateadd", "macro.dbt.date_trunc"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.674582, "supported_languages": null}, "macro.dbt.default__last_day": {"name": "default__last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.default__last_day", "macro_sql": "{% macro default__last_day(date, datepart) -%}\n    {{dbt.default_last_day(date, datepart)}}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default_last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.674709, "supported_languages": null}, "macro.dbt.split_part": {"name": "split_part", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt.split_part", "macro_sql": "{% macro split_part(string_text, delimiter_text, part_number) %}\n  {{ return(adapter.dispatch('split_part', 'dbt') (string_text, delimiter_text, part_number)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__split_part"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.675154, "supported_languages": null}, "macro.dbt.default__split_part": {"name": "default__split_part", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt.default__split_part", "macro_sql": "{% macro default__split_part(string_text, delimiter_text, part_number) %}\n\n    split_part(\n        {{ string_text }},\n        {{ delimiter_text }},\n        {{ part_number }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.675293, "supported_languages": null}, "macro.dbt._split_part_negative": {"name": "_split_part_negative", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt._split_part_negative", "macro_sql": "{% macro _split_part_negative(string_text, delimiter_text, part_number) %}\n\n    split_part(\n        {{ string_text }},\n        {{ delimiter_text }},\n          length({{ string_text }})\n          - length(\n              replace({{ string_text }},  {{ delimiter_text }}, '')\n          ) + 2 {{ part_number }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.67554, "supported_languages": null}, "macro.dbt.date_trunc": {"name": "date_trunc", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_trunc.sql", "original_file_path": "macros/utils/date_trunc.sql", "unique_id": "macro.dbt.date_trunc", "macro_sql": "{% macro date_trunc(datepart, date) -%}\n  {{ return(adapter.dispatch('date_trunc', 'dbt') (datepart, date)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__date_trunc"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.675781, "supported_languages": null}, "macro.dbt.default__date_trunc": {"name": "default__date_trunc", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_trunc.sql", "original_file_path": "macros/utils/date_trunc.sql", "unique_id": "macro.dbt.default__date_trunc", "macro_sql": "{% macro default__date_trunc(datepart, date) -%}\n    date_trunc('{{datepart}}', {{date}})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.67589, "supported_languages": null}, "macro.dbt.array_construct": {"name": "array_construct", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_construct.sql", "original_file_path": "macros/utils/array_construct.sql", "unique_id": "macro.dbt.array_construct", "macro_sql": "{% macro array_construct(inputs=[], data_type=api.Column.translate_type('integer')) -%}\n  {{ return(adapter.dispatch('array_construct', 'dbt')(inputs, data_type)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_construct"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.676214, "supported_languages": null}, "macro.dbt.default__array_construct": {"name": "default__array_construct", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_construct.sql", "original_file_path": "macros/utils/array_construct.sql", "unique_id": "macro.dbt.default__array_construct", "macro_sql": "{% macro default__array_construct(inputs, data_type) -%}\n    {% if inputs|length > 0 %}\n    array[ {{ inputs|join(' , ') }} ]\n    {% else %}\n    array[]::{{data_type}}[]\n    {% endif %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.676425, "supported_languages": null}, "macro.dbt.array_append": {"name": "array_append", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_append.sql", "original_file_path": "macros/utils/array_append.sql", "unique_id": "macro.dbt.array_append", "macro_sql": "{% macro array_append(array, new_element) -%}\n  {{ return(adapter.dispatch('array_append', 'dbt')(array, new_element)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_append"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.676668, "supported_languages": null}, "macro.dbt.default__array_append": {"name": "default__array_append", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_append.sql", "original_file_path": "macros/utils/array_append.sql", "unique_id": "macro.dbt.default__array_append", "macro_sql": "{% macro default__array_append(array, new_element) -%}\n    array_append({{ array }}, {{ new_element }})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.676778, "supported_languages": null}, "macro.dbt.create_schema": {"name": "create_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.create_schema", "macro_sql": "{% macro create_schema(relation) -%}\n  {{ adapter.dispatch('create_schema', 'dbt')(relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_schema"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6771042, "supported_languages": null}, "macro.dbt.default__create_schema": {"name": "default__create_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.default__create_schema", "macro_sql": "{% macro default__create_schema(relation) -%}\n  {%- call statement('create_schema') -%}\n    create schema if not exists {{ relation.without_identifier() }}\n  {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.677264, "supported_languages": null}, "macro.dbt.drop_schema": {"name": "drop_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.drop_schema", "macro_sql": "{% macro drop_schema(relation) -%}\n  {{ adapter.dispatch('drop_schema', 'dbt')(relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__drop_schema"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.677402, "supported_languages": null}, "macro.dbt.default__drop_schema": {"name": "default__drop_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.default__drop_schema", "macro_sql": "{% macro default__drop_schema(relation) -%}\n  {%- call statement('drop_schema') -%}\n    drop schema if exists {{ relation.without_identifier() }} cascade\n  {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.677574, "supported_languages": null}, "macro.dbt.current_timestamp": {"name": "current_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp", "macro_sql": "{%- macro current_timestamp() -%}\n    {{ adapter.dispatch('current_timestamp', 'dbt')() }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.677997, "supported_languages": null}, "macro.dbt.default__current_timestamp": {"name": "default__current_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp", "macro_sql": "{% macro default__current_timestamp() -%}\n  {{ exceptions.raise_not_implemented(\n    'current_timestamp macro not implemented for adapter ' + adapter.type()) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6781251, "supported_languages": null}, "macro.dbt.snapshot_get_time": {"name": "snapshot_get_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.snapshot_get_time", "macro_sql": "\n\n{%- macro snapshot_get_time() -%}\n    {{ adapter.dispatch('snapshot_get_time', 'dbt')() }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_get_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.678248, "supported_languages": null}, "macro.dbt.default__snapshot_get_time": {"name": "default__snapshot_get_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__snapshot_get_time", "macro_sql": "{% macro default__snapshot_get_time() %}\n    {{ current_timestamp() }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.678338, "supported_languages": null}, "macro.dbt.current_timestamp_backcompat": {"name": "current_timestamp_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp_backcompat", "macro_sql": "{% macro current_timestamp_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__current_timestamp_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.678478, "supported_languages": null}, "macro.dbt.default__current_timestamp_backcompat": {"name": "default__current_timestamp_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp_backcompat", "macro_sql": "{% macro default__current_timestamp_backcompat() %}\n    current_timestamp::timestamp\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.678539, "supported_languages": null}, "macro.dbt.current_timestamp_in_utc_backcompat": {"name": "current_timestamp_in_utc_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp_in_utc_backcompat", "macro_sql": "{% macro current_timestamp_in_utc_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_in_utc_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__current_timestamp_in_utc_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6786802, "supported_languages": null}, "macro.dbt.default__current_timestamp_in_utc_backcompat": {"name": "default__current_timestamp_in_utc_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp_in_utc_backcompat", "macro_sql": "{% macro default__current_timestamp_in_utc_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp_backcompat", "macro.dbt.default__current_timestamp_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.678824, "supported_languages": null}, "macro.dbt.get_create_index_sql": {"name": "get_create_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.get_create_index_sql", "macro_sql": "{% macro get_create_index_sql(relation, index_dict) -%}\n  {{ return(adapter.dispatch('get_create_index_sql', 'dbt')(relation, index_dict)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_index_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6792178, "supported_languages": null}, "macro.dbt.default__get_create_index_sql": {"name": "default__get_create_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__get_create_index_sql", "macro_sql": "{% macro default__get_create_index_sql(relation, index_dict) -%}\n  {% do return(None) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.679399, "supported_languages": null}, "macro.dbt.create_indexes": {"name": "create_indexes", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.create_indexes", "macro_sql": "{% macro create_indexes(relation) -%}\n  {{ adapter.dispatch('create_indexes', 'dbt')(relation) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.679533, "supported_languages": null}, "macro.dbt.default__create_indexes": {"name": "default__create_indexes", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__create_indexes", "macro_sql": "{% macro default__create_indexes(relation) -%}\n  {%- set _indexes = config.get('indexes', default=[]) -%}\n\n  {% for _index_dict in _indexes %}\n    {% set create_index_sql = get_create_index_sql(relation, _index_dict) %}\n    {% if create_index_sql %}\n      {% do run_query(create_index_sql) %}\n    {% endif %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_create_index_sql", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.679878, "supported_languages": null}, "macro.dbt.make_intermediate_relation": {"name": "make_intermediate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_intermediate_relation", "macro_sql": "{% macro make_intermediate_relation(base_relation, suffix='__dbt_tmp') %}\n  {{ return(adapter.dispatch('make_intermediate_relation', 'dbt')(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_intermediate_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.682687, "supported_languages": null}, "macro.dbt.default__make_intermediate_relation": {"name": "default__make_intermediate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_intermediate_relation", "macro_sql": "{% macro default__make_intermediate_relation(base_relation, suffix) %}\n    {{ return(default__make_temp_relation(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_temp_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.682827, "supported_languages": null}, "macro.dbt.make_temp_relation": {"name": "make_temp_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_temp_relation", "macro_sql": "{% macro make_temp_relation(base_relation, suffix='__dbt_tmp') %}\n  {{ return(adapter.dispatch('make_temp_relation', 'dbt')(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__make_temp_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.683017, "supported_languages": null}, "macro.dbt.default__make_temp_relation": {"name": "default__make_temp_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_temp_relation", "macro_sql": "{% macro default__make_temp_relation(base_relation, suffix) %}\n    {%- set temp_identifier = base_relation.identifier ~ suffix -%}\n    {%- set temp_relation = base_relation.incorporate(\n                                path={\"identifier\": temp_identifier}) -%}\n\n    {{ return(temp_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.683267, "supported_languages": null}, "macro.dbt.make_backup_relation": {"name": "make_backup_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_backup_relation", "macro_sql": "{% macro make_backup_relation(base_relation, backup_relation_type, suffix='__dbt_backup') %}\n    {{ return(adapter.dispatch('make_backup_relation', 'dbt')(base_relation, backup_relation_type, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_backup_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.68348, "supported_languages": null}, "macro.dbt.default__make_backup_relation": {"name": "default__make_backup_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_backup_relation", "macro_sql": "{% macro default__make_backup_relation(base_relation, backup_relation_type, suffix) %}\n    {%- set backup_identifier = base_relation.identifier ~ suffix -%}\n    {%- set backup_relation = base_relation.incorporate(\n                                  path={\"identifier\": backup_identifier},\n                                  type=backup_relation_type\n    ) -%}\n    {{ return(backup_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.683755, "supported_languages": null}, "macro.dbt.drop_relation": {"name": "drop_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.drop_relation", "macro_sql": "{% macro drop_relation(relation) -%}\n  {{ return(adapter.dispatch('drop_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__drop_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.683913, "supported_languages": null}, "macro.dbt.default__drop_relation": {"name": "default__drop_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__drop_relation", "macro_sql": "{% macro default__drop_relation(relation) -%}\n  {% call statement('drop_relation', auto_begin=False) -%}\n    drop {{ relation.type }} if exists {{ relation }} cascade\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.684098, "supported_languages": null}, "macro.dbt.truncate_relation": {"name": "truncate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.truncate_relation", "macro_sql": "{% macro truncate_relation(relation) -%}\n  {{ return(adapter.dispatch('truncate_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__truncate_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.684253, "supported_languages": null}, "macro.dbt.default__truncate_relation": {"name": "default__truncate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__truncate_relation", "macro_sql": "{% macro default__truncate_relation(relation) -%}\n  {% call statement('truncate_relation') -%}\n    truncate table {{ relation }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6843882, "supported_languages": null}, "macro.dbt.rename_relation": {"name": "rename_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.rename_relation", "macro_sql": "{% macro rename_relation(from_relation, to_relation) -%}\n  {{ return(adapter.dispatch('rename_relation', 'dbt')(from_relation, to_relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__rename_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.684561, "supported_languages": null}, "macro.dbt.default__rename_relation": {"name": "default__rename_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__rename_relation", "macro_sql": "{% macro default__rename_relation(from_relation, to_relation) -%}\n  {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}\n  {% call statement('rename_relation') -%}\n    alter table {{ from_relation }} rename to {{ target_name }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.684798, "supported_languages": null}, "macro.dbt.get_or_create_relation": {"name": "get_or_create_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.get_or_create_relation", "macro_sql": "{% macro get_or_create_relation(database, schema, identifier, type) -%}\n  {{ return(adapter.dispatch('get_or_create_relation', 'dbt')(database, schema, identifier, type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_or_create_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.685013, "supported_languages": null}, "macro.dbt.default__get_or_create_relation": {"name": "default__get_or_create_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__get_or_create_relation", "macro_sql": "{% macro default__get_or_create_relation(database, schema, identifier, type) %}\n  {%- set target_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) %}\n\n  {% if target_relation %}\n    {% do return([true, target_relation]) %}\n  {% endif %}\n\n  {%- set new_relation = api.Relation.create(\n      database=database,\n      schema=schema,\n      identifier=identifier,\n      type=type\n  ) -%}\n  {% do return([false, new_relation]) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.685487, "supported_languages": null}, "macro.dbt.load_cached_relation": {"name": "load_cached_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.load_cached_relation", "macro_sql": "{% macro load_cached_relation(relation) %}\n  {% do return(adapter.get_relation(\n    database=relation.database,\n    schema=relation.schema,\n    identifier=relation.identifier\n  )) -%}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.68575, "supported_languages": null}, "macro.dbt.load_relation": {"name": "load_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.load_relation", "macro_sql": "{% macro load_relation(relation) %}\n    {{ return(load_cached_relation(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6858728, "supported_languages": null}, "macro.dbt.drop_relation_if_exists": {"name": "drop_relation_if_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.drop_relation_if_exists", "macro_sql": "{% macro drop_relation_if_exists(relation) %}\n  {% if relation is not none %}\n    {{ adapter.drop_relation(relation) }}\n  {% endif %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6860359, "supported_languages": null}, "macro.dbt.collect_freshness": {"name": "collect_freshness", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/freshness.sql", "original_file_path": "macros/adapters/freshness.sql", "unique_id": "macro.dbt.collect_freshness", "macro_sql": "{% macro collect_freshness(source, loaded_at_field, filter) %}\n  {{ return(adapter.dispatch('collect_freshness', 'dbt')(source, loaded_at_field, filter))}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__collect_freshness"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.686399, "supported_languages": null}, "macro.dbt.default__collect_freshness": {"name": "default__collect_freshness", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/freshness.sql", "original_file_path": "macros/adapters/freshness.sql", "unique_id": "macro.dbt.default__collect_freshness", "macro_sql": "{% macro default__collect_freshness(source, loaded_at_field, filter) %}\n  {% call statement('collect_freshness', fetch_result=True, auto_begin=False) -%}\n    select\n      max({{ loaded_at_field }}) as max_loaded_at,\n      {{ current_timestamp() }} as snapshotted_at\n    from {{ source }}\n    {% if filter %}\n    where {{ filter }}\n    {% endif %}\n  {% endcall %}\n  {{ return(load_result('collect_freshness').table) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.686757, "supported_languages": null}, "macro.dbt.copy_grants": {"name": "copy_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.copy_grants", "macro_sql": "{% macro copy_grants() %}\n    {{ return(adapter.dispatch('copy_grants', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__copy_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.688231, "supported_languages": null}, "macro.dbt.default__copy_grants": {"name": "default__copy_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__copy_grants", "macro_sql": "{% macro default__copy_grants() %}\n    {{ return(True) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.688329, "supported_languages": null}, "macro.dbt.support_multiple_grantees_per_dcl_statement": {"name": "support_multiple_grantees_per_dcl_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.support_multiple_grantees_per_dcl_statement", "macro_sql": "{% macro support_multiple_grantees_per_dcl_statement() %}\n    {{ return(adapter.dispatch('support_multiple_grantees_per_dcl_statement', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__support_multiple_grantees_per_dcl_statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.688475, "supported_languages": null}, "macro.dbt.default__support_multiple_grantees_per_dcl_statement": {"name": "default__support_multiple_grantees_per_dcl_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__support_multiple_grantees_per_dcl_statement", "macro_sql": "\n\n{%- macro default__support_multiple_grantees_per_dcl_statement() -%}\n    {{ return(True) }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.688568, "supported_languages": null}, "macro.dbt.should_revoke": {"name": "should_revoke", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.should_revoke", "macro_sql": "{% macro should_revoke(existing_relation, full_refresh_mode=True) %}\n\n    {% if not existing_relation %}\n        {#-- The table doesn't already exist, so no grants to copy over --#}\n        {{ return(False) }}\n    {% elif full_refresh_mode %}\n        {#-- The object is being REPLACED -- whether grants are copied over depends on the value of user config --#}\n        {{ return(copy_grants()) }}\n    {% else %}\n        {#-- The table is being merged/upserted/inserted -- grants will be carried over --#}\n        {{ return(True) }}\n    {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.copy_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.688861, "supported_languages": null}, "macro.dbt.get_show_grant_sql": {"name": "get_show_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_show_grant_sql", "macro_sql": "{% macro get_show_grant_sql(relation) %}\n    {{ return(adapter.dispatch(\"get_show_grant_sql\", \"dbt\")(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_show_grant_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.689023, "supported_languages": null}, "macro.dbt.default__get_show_grant_sql": {"name": "default__get_show_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_show_grant_sql", "macro_sql": "{% macro default__get_show_grant_sql(relation) %}\n    show grants on {{ relation }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.689109, "supported_languages": null}, "macro.dbt.get_grant_sql": {"name": "get_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_grant_sql", "macro_sql": "{% macro get_grant_sql(relation, privilege, grantees) %}\n    {{ return(adapter.dispatch('get_grant_sql', 'dbt')(relation, privilege, grantees)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_grant_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.689307, "supported_languages": null}, "macro.dbt.default__get_grant_sql": {"name": "default__get_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_grant_sql", "macro_sql": "\n\n{%- macro default__get_grant_sql(relation, privilege, grantees) -%}\n    grant {{ privilege }} on {{ relation }} to {{ grantees | join(', ') }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.689466, "supported_languages": null}, "macro.dbt.get_revoke_sql": {"name": "get_revoke_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_revoke_sql", "macro_sql": "{% macro get_revoke_sql(relation, privilege, grantees) %}\n    {{ return(adapter.dispatch('get_revoke_sql', 'dbt')(relation, privilege, grantees)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_revoke_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.689657, "supported_languages": null}, "macro.dbt.default__get_revoke_sql": {"name": "default__get_revoke_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_revoke_sql", "macro_sql": "\n\n{%- macro default__get_revoke_sql(relation, privilege, grantees) -%}\n    revoke {{ privilege }} on {{ relation }} from {{ grantees | join(', ') }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6898172, "supported_languages": null}, "macro.dbt.get_dcl_statement_list": {"name": "get_dcl_statement_list", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_dcl_statement_list", "macro_sql": "{% macro get_dcl_statement_list(relation, grant_config, get_dcl_macro) %}\n    {{ return(adapter.dispatch('get_dcl_statement_list', 'dbt')(relation, grant_config, get_dcl_macro)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_dcl_statement_list"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.690012, "supported_languages": null}, "macro.dbt.default__get_dcl_statement_list": {"name": "default__get_dcl_statement_list", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_dcl_statement_list", "macro_sql": "\n\n{%- macro default__get_dcl_statement_list(relation, grant_config, get_dcl_macro) -%}\n    {#\n      -- Unpack grant_config into specific privileges and the set of users who need them granted/revoked.\n      -- Depending on whether this database supports multiple grantees per statement, pass in the list of\n      -- all grantees per privilege, or (if not) template one statement per privilege-grantee pair.\n      -- `get_dcl_macro` will be either `get_grant_sql` or `get_revoke_sql`\n    #}\n    {%- set dcl_statements = [] -%}\n    {%- for privilege, grantees in grant_config.items() %}\n        {%- if support_multiple_grantees_per_dcl_statement() and grantees -%}\n          {%- set dcl = get_dcl_macro(relation, privilege, grantees) -%}\n          {%- do dcl_statements.append(dcl) -%}\n        {%- else -%}\n          {%- for grantee in grantees -%}\n              {% set dcl = get_dcl_macro(relation, privilege, [grantee]) %}\n              {%- do dcl_statements.append(dcl) -%}\n          {% endfor -%}\n        {%- endif -%}\n    {%- endfor -%}\n    {{ return(dcl_statements) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.support_multiple_grantees_per_dcl_statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.690586, "supported_languages": null}, "macro.dbt.call_dcl_statements": {"name": "call_dcl_statements", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.call_dcl_statements", "macro_sql": "{% macro call_dcl_statements(dcl_statement_list) %}\n    {{ return(adapter.dispatch(\"call_dcl_statements\", \"dbt\")(dcl_statement_list)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__call_dcl_statements"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.690748, "supported_languages": null}, "macro.dbt.default__call_dcl_statements": {"name": "default__call_dcl_statements", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__call_dcl_statements", "macro_sql": "{% macro default__call_dcl_statements(dcl_statement_list) %}\n    {#\n      -- By default, supply all grant + revoke statements in a single semicolon-separated block,\n      -- so that they're all processed together.\n\n      -- Some databases do not support this. Those adapters will need to override this macro\n      -- to run each statement individually.\n    #}\n    {% call statement('grants') %}\n        {% for dcl_statement in dcl_statement_list %}\n            {{ dcl_statement }};\n        {% endfor %}\n    {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.690955, "supported_languages": null}, "macro.dbt.apply_grants": {"name": "apply_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.apply_grants", "macro_sql": "{% macro apply_grants(relation, grant_config, should_revoke) %}\n    {{ return(adapter.dispatch(\"apply_grants\", \"dbt\")(relation, grant_config, should_revoke)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__apply_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.691225, "supported_languages": null}, "macro.dbt.default__apply_grants": {"name": "default__apply_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__apply_grants", "macro_sql": "{% macro default__apply_grants(relation, grant_config, should_revoke=True) %}\n    {#-- If grant_config is {} or None, this is a no-op --#}\n    {% if grant_config %}\n        {% if should_revoke %}\n            {#-- We think previous grants may have carried over --#}\n            {#-- Show current grants and calculate diffs --#}\n            {% set current_grants_table = run_query(get_show_grant_sql(relation)) %}\n            {% set current_grants_dict = adapter.standardize_grants_dict(current_grants_table) %}\n            {% set needs_granting = diff_of_two_dicts(grant_config, current_grants_dict) %}\n            {% set needs_revoking = diff_of_two_dicts(current_grants_dict, grant_config) %}\n            {% if not (needs_granting or needs_revoking) %}\n                {{ log('On ' ~ relation ~': All grants are in place, no revocation or granting needed.')}}\n            {% endif %}\n        {% else %}\n            {#-- We don't think there's any chance of previous grants having carried over. --#}\n            {#-- Jump straight to granting what the user has configured. --#}\n            {% set needs_revoking = {} %}\n            {% set needs_granting = grant_config %}\n        {% endif %}\n        {% if needs_granting or needs_revoking %}\n            {% set revoke_statement_list = get_dcl_statement_list(relation, needs_revoking, get_revoke_sql) %}\n            {% set grant_statement_list = get_dcl_statement_list(relation, needs_granting, get_grant_sql) %}\n            {% set dcl_statement_list = revoke_statement_list + grant_statement_list %}\n            {% if dcl_statement_list %}\n                {{ call_dcl_statements(dcl_statement_list) }}\n            {% endif %}\n        {% endif %}\n    {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query", "macro.dbt.get_show_grant_sql", "macro.dbt.get_dcl_statement_list", "macro.dbt.call_dcl_statements"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.692201, "supported_languages": null}, "macro.dbt.alter_column_comment": {"name": "alter_column_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.alter_column_comment", "macro_sql": "{% macro alter_column_comment(relation, column_dict) -%}\n  {{ return(adapter.dispatch('alter_column_comment', 'dbt')(relation, column_dict)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_column_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.692799, "supported_languages": null}, "macro.dbt.default__alter_column_comment": {"name": "default__alter_column_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__alter_column_comment", "macro_sql": "{% macro default__alter_column_comment(relation, column_dict) -%}\n  {{ exceptions.raise_not_implemented(\n    'alter_column_comment macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.692943, "supported_languages": null}, "macro.dbt.alter_relation_comment": {"name": "alter_relation_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.alter_relation_comment", "macro_sql": "{% macro alter_relation_comment(relation, relation_comment) -%}\n  {{ return(adapter.dispatch('alter_relation_comment', 'dbt')(relation, relation_comment)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_relation_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6931179, "supported_languages": null}, "macro.dbt.default__alter_relation_comment": {"name": "default__alter_relation_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__alter_relation_comment", "macro_sql": "{% macro default__alter_relation_comment(relation, relation_comment) -%}\n  {{ exceptions.raise_not_implemented(\n    'alter_relation_comment macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.69326, "supported_languages": null}, "macro.dbt.persist_docs": {"name": "persist_docs", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.persist_docs", "macro_sql": "{% macro persist_docs(relation, model, for_relation=true, for_columns=true) -%}\n  {{ return(adapter.dispatch('persist_docs', 'dbt')(relation, model, for_relation, for_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.693491, "supported_languages": null}, "macro.dbt.default__persist_docs": {"name": "default__persist_docs", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__persist_docs", "macro_sql": "{% macro default__persist_docs(relation, model, for_relation, for_columns) -%}\n  {% if for_relation and config.persist_relation_docs() and model.description %}\n    {% do run_query(alter_relation_comment(relation, model.description)) %}\n  {% endif %}\n\n  {% if for_columns and config.persist_column_docs() and model.columns %}\n    {% do run_query(alter_column_comment(relation, model.columns)) %}\n  {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query", "macro.dbt.alter_relation_comment", "macro.dbt.alter_column_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.693917, "supported_languages": null}, "macro.dbt.get_catalog": {"name": "get_catalog", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.get_catalog", "macro_sql": "{% macro get_catalog(information_schema, schemas) -%}\n  {{ return(adapter.dispatch('get_catalog', 'dbt')(information_schema, schemas)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_catalog"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.695193, "supported_languages": null}, "macro.dbt.default__get_catalog": {"name": "default__get_catalog", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__get_catalog", "macro_sql": "{% macro default__get_catalog(information_schema, schemas) -%}\n\n  {% set typename = adapter.type() %}\n  {% set msg -%}\n    get_catalog not implemented for {{ typename }}\n  {%- endset %}\n\n  {{ exceptions.raise_compiler_error(msg) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6954129, "supported_languages": null}, "macro.dbt.information_schema_name": {"name": "information_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.information_schema_name", "macro_sql": "{% macro information_schema_name(database) %}\n  {{ return(adapter.dispatch('information_schema_name', 'dbt')(database)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__information_schema_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.695571, "supported_languages": null}, "macro.dbt.default__information_schema_name": {"name": "default__information_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__information_schema_name", "macro_sql": "{% macro default__information_schema_name(database) -%}\n  {%- if database -%}\n    {{ database }}.INFORMATION_SCHEMA\n  {%- else -%}\n    INFORMATION_SCHEMA\n  {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.695704, "supported_languages": null}, "macro.dbt.list_schemas": {"name": "list_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.list_schemas", "macro_sql": "{% macro list_schemas(database) -%}\n  {{ return(adapter.dispatch('list_schemas', 'dbt')(database)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__list_schemas"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6958551, "supported_languages": null}, "macro.dbt.default__list_schemas": {"name": "default__list_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__list_schemas", "macro_sql": "{% macro default__list_schemas(database) -%}\n  {% set sql %}\n    select distinct schema_name\n    from {{ information_schema_name(database) }}.SCHEMATA\n    where catalog_name ilike '{{ database }}'\n  {% endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.information_schema_name", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.696067, "supported_languages": null}, "macro.dbt.check_schema_exists": {"name": "check_schema_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.check_schema_exists", "macro_sql": "{% macro check_schema_exists(information_schema, schema) -%}\n  {{ return(adapter.dispatch('check_schema_exists', 'dbt')(information_schema, schema)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__check_schema_exists"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6962419, "supported_languages": null}, "macro.dbt.default__check_schema_exists": {"name": "default__check_schema_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__check_schema_exists", "macro_sql": "{% macro default__check_schema_exists(information_schema, schema) -%}\n  {% set sql -%}\n        select count(*)\n        from {{ information_schema.replace(information_schema_view='SCHEMATA') }}\n        where catalog_name='{{ information_schema.database }}'\n          and schema_name='{{ schema }}'\n  {%- endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.replace", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.696498, "supported_languages": null}, "macro.dbt.list_relations_without_caching": {"name": "list_relations_without_caching", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.list_relations_without_caching", "macro_sql": "{% macro list_relations_without_caching(schema_relation) %}\n  {{ return(adapter.dispatch('list_relations_without_caching', 'dbt')(schema_relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__list_relations_without_caching"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.696657, "supported_languages": null}, "macro.dbt.default__list_relations_without_caching": {"name": "default__list_relations_without_caching", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__list_relations_without_caching", "macro_sql": "{% macro default__list_relations_without_caching(schema_relation) %}\n  {{ exceptions.raise_not_implemented(\n    'list_relations_without_caching macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6967921, "supported_languages": null}, "macro.dbt.get_columns_in_relation": {"name": "get_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_columns_in_relation", "macro_sql": "{% macro get_columns_in_relation(relation) -%}\n  {{ return(adapter.dispatch('get_columns_in_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_columns_in_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.698245, "supported_languages": null}, "macro.dbt.default__get_columns_in_relation": {"name": "default__get_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_columns_in_relation", "macro_sql": "{% macro default__get_columns_in_relation(relation) -%}\n  {{ exceptions.raise_not_implemented(\n    'get_columns_in_relation macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.698378, "supported_languages": null}, "macro.dbt.sql_convert_columns_in_relation": {"name": "sql_convert_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.sql_convert_columns_in_relation", "macro_sql": "{% macro sql_convert_columns_in_relation(table) -%}\n  {% set columns = [] %}\n  {% for row in table %}\n    {% do columns.append(api.Column(*row)) %}\n  {% endfor %}\n  {{ return(columns) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.69872, "supported_languages": null}, "macro.dbt.get_columns_in_query": {"name": "get_columns_in_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_columns_in_query", "macro_sql": "{% macro get_columns_in_query(select_sql) -%}\n  {{ return(adapter.dispatch('get_columns_in_query', 'dbt')(select_sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_columns_in_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.698879, "supported_languages": null}, "macro.dbt.default__get_columns_in_query": {"name": "default__get_columns_in_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_columns_in_query", "macro_sql": "{% macro default__get_columns_in_query(select_sql) %}\n    {% call statement('get_columns_in_query', fetch_result=True, auto_begin=False) -%}\n        select * from (\n            {{ select_sql }}\n        ) as __dbt_sbq\n        where false\n        limit 0\n    {% endcall %}\n\n    {{ return(load_result('get_columns_in_query').table.columns | map(attribute='name') | list) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.699171, "supported_languages": null}, "macro.dbt.alter_column_type": {"name": "alter_column_type", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.alter_column_type", "macro_sql": "{% macro alter_column_type(relation, column_name, new_column_type) -%}\n  {{ return(adapter.dispatch('alter_column_type', 'dbt')(relation, column_name, new_column_type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_column_type"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.699368, "supported_languages": null}, "macro.dbt.default__alter_column_type": {"name": "default__alter_column_type", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__alter_column_type", "macro_sql": "{% macro default__alter_column_type(relation, column_name, new_column_type) -%}\n  {#\n    1. Create a new column (w/ temp name and correct type)\n    2. Copy data over to it\n    3. Drop the existing column (cascade!)\n    4. Rename the new column to existing column\n  #}\n  {%- set tmp_column = column_name + \"__dbt_alter\" -%}\n\n  {% call statement('alter_column_type') %}\n    alter table {{ relation }} add column {{ adapter.quote(tmp_column) }} {{ new_column_type }};\n    update {{ relation }} set {{ adapter.quote(tmp_column) }} = {{ adapter.quote(column_name) }};\n    alter table {{ relation }} drop column {{ adapter.quote(column_name) }} cascade;\n    alter table {{ relation }} rename column {{ adapter.quote(tmp_column) }} to {{ adapter.quote(column_name) }}\n  {% endcall %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.6998851, "supported_languages": null}, "macro.dbt.alter_relation_add_remove_columns": {"name": "alter_relation_add_remove_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.alter_relation_add_remove_columns", "macro_sql": "{% macro alter_relation_add_remove_columns(relation, add_columns = none, remove_columns = none) -%}\n  {{ return(adapter.dispatch('alter_relation_add_remove_columns', 'dbt')(relation, add_columns, remove_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_relation_add_remove_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.700109, "supported_languages": null}, "macro.dbt.default__alter_relation_add_remove_columns": {"name": "default__alter_relation_add_remove_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__alter_relation_add_remove_columns", "macro_sql": "{% macro default__alter_relation_add_remove_columns(relation, add_columns, remove_columns) %}\n\n  {% if add_columns is none %}\n    {% set add_columns = [] %}\n  {% endif %}\n  {% if remove_columns is none %}\n    {% set remove_columns = [] %}\n  {% endif %}\n\n  {% set sql -%}\n\n     alter {{ relation.type }} {{ relation }}\n\n            {% for column in add_columns %}\n               add column {{ column.name }} {{ column.data_type }}{{ ',' if not loop.last }}\n            {% endfor %}{{ ',' if add_columns and remove_columns }}\n\n            {% for column in remove_columns %}\n                drop column {{ column.name }}{{ ',' if not loop.last }}\n            {% endfor %}\n\n  {%- endset -%}\n\n  {% do run_query(sql) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.700779, "supported_languages": null}, "macro.dbt.resolve_model_name": {"name": "resolve_model_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.resolve_model_name", "macro_sql": "{% macro resolve_model_name(input_model_name) %}\n    {{ return(adapter.dispatch('resolve_model_name', 'dbt')(input_model_name)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.701974, "supported_languages": null}, "macro.dbt.default__resolve_model_name": {"name": "default__resolve_model_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.default__resolve_model_name", "macro_sql": "\n\n{%- macro default__resolve_model_name(input_model_name) -%}\n    {{  input_model_name | string | replace('\"', '\\\"') }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.702105, "supported_languages": null}, "macro.dbt.build_ref_function": {"name": "build_ref_function", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_ref_function", "macro_sql": "{% macro build_ref_function(model) %}\n\n    {%- set ref_dict = {} -%}\n    {%- for _ref in model.refs -%}\n        {%- set resolved = ref(*_ref) -%}\n        {%- do ref_dict.update({_ref | join('.'): resolve_model_name(resolved)}) -%}\n    {%- endfor -%}\n\ndef ref(*args,dbt_load_df_function):\n    refs = {{ ref_dict | tojson }}\n    key = '.'.join(args)\n    return dbt_load_df_function(refs[key])\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.702455, "supported_languages": null}, "macro.dbt.build_source_function": {"name": "build_source_function", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_source_function", "macro_sql": "{% macro build_source_function(model) %}\n\n    {%- set source_dict = {} -%}\n    {%- for _source in model.sources -%}\n        {%- set resolved = source(*_source) -%}\n        {%- do source_dict.update({_source | join('.'): resolve_model_name(resolved)}) -%}\n    {%- endfor -%}\n\ndef source(*args, dbt_load_df_function):\n    sources = {{ source_dict | tojson }}\n    key = '.'.join(args)\n    return dbt_load_df_function(sources[key])\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.702801, "supported_languages": null}, "macro.dbt.build_config_dict": {"name": "build_config_dict", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_config_dict", "macro_sql": "{% macro build_config_dict(model) %}\n    {%- set config_dict = {} -%}\n    {% set config_dbt_used = zip(model.config.config_keys_used, model.config.config_keys_defaults) | list %}\n    {%- for key, default in config_dbt_used -%}\n        {# weird type testing with enum, would be much easier to write this logic in Python! #}\n        {%- if key == \"language\" -%}\n          {%- set value = \"python\" -%}\n        {%- endif -%}\n        {%- set value = model.config.get(key, default) -%}\n        {%- do config_dict.update({key: value}) -%}\n    {%- endfor -%}\nconfig_dict = {{ config_dict }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.7033, "supported_languages": null}, "macro.dbt.py_script_postfix": {"name": "py_script_postfix", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.py_script_postfix", "macro_sql": "{% macro py_script_postfix(model) %}\n# This part is user provided model code\n# you will need to copy the next section to run the code\n# COMMAND ----------\n# this part is dbt logic for get ref work, do not modify\n\n{{ build_ref_function(model ) }}\n{{ build_source_function(model ) }}\n{{ build_config_dict(model) }}\n\nclass config:\n    def __init__(self, *args, **kwargs):\n        pass\n\n    @staticmethod\n    def get(key, default=None):\n        return config_dict.get(key, default)\n\nclass this:\n    \"\"\"dbt.this() or dbt.this.identifier\"\"\"\n    database = \"{{ this.database }}\"\n    schema = \"{{ this.schema }}\"\n    identifier = \"{{ this.identifier }}\"\n    {% set this_relation_name = resolve_model_name(this) %}\n    def __repr__(self):\n        return '{{ this_relation_name  }}'\n\n\nclass dbtObj:\n    def __init__(self, load_df_function) -> None:\n        self.source = lambda *args: source(*args, dbt_load_df_function=load_df_function)\n        self.ref = lambda *args: ref(*args, dbt_load_df_function=load_df_function)\n        self.config = config\n        self.this = this()\n        self.is_incremental = {{ is_incremental() }}\n\n# COMMAND ----------\n{{py_script_comment()}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.build_ref_function", "macro.dbt.build_source_function", "macro.dbt.build_config_dict", "macro.dbt.resolve_model_name", "macro.dbt.is_incremental", "macro.dbt.py_script_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.703707, "supported_languages": null}, "macro.dbt.py_script_comment": {"name": "py_script_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.py_script_comment", "macro_sql": "{%macro py_script_comment()%}\n{%endmacro%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.7037702, "supported_languages": null}, "macro.dbt.test_unique": {"name": "test_unique", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_unique", "macro_sql": "{% test unique(model, column_name) %}\n    {% set macro = adapter.dispatch('test_unique', 'dbt') %}\n    {{ macro(model, column_name) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_unique"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.704208, "supported_languages": null}, "macro.dbt.test_not_null": {"name": "test_not_null", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_not_null", "macro_sql": "{% test not_null(model, column_name) %}\n    {% set macro = adapter.dispatch('test_not_null', 'dbt') %}\n    {{ macro(model, column_name) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_not_null"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.704405, "supported_languages": null}, "macro.dbt.test_accepted_values": {"name": "test_accepted_values", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_accepted_values", "macro_sql": "{% test accepted_values(model, column_name, values, quote=True) %}\n    {% set macro = adapter.dispatch('test_accepted_values', 'dbt') %}\n    {{ macro(model, column_name, values, quote) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_accepted_values"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.704649, "supported_languages": null}, "macro.dbt.test_relationships": {"name": "test_relationships", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_relationships", "macro_sql": "{% test relationships(model, column_name, to, field) %}\n    {% set macro = adapter.dispatch('test_relationships', 'dbt') %}\n    {{ macro(model, column_name, to, field) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_relationships"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1680025829.704882, "supported_languages": null}}, "docs": {"doc.jaffle_shop.__overview__": {"name": "__overview__", "resource_type": "doc", "package_name": "jaffle_shop", "path": "overview.md", "original_file_path": "models/overview.md", "unique_id": "doc.jaffle_shop.__overview__", "block_contents": "## Data Documentation for Jaffle Shop\n\n`jaffle_shop` is a fictional ecommerce store.\n\nThis [dbt](https://www.getdbt.com/) project is for testing out code.\n\nThe source code can be found [here](https://github.com/clrcrl/jaffle_shop)."}, "doc.jaffle_shop.orders_status": {"name": "orders_status", "resource_type": "doc", "package_name": "jaffle_shop", "path": "docs.md", "original_file_path": "models/docs.md", "unique_id": "doc.jaffle_shop.orders_status", "block_contents": "Orders can be one of the following statuses:\n\n| status         | description                                                                                                            |\n|----------------|------------------------------------------------------------------------------------------------------------------------|\n| placed         | The order has been placed but has not yet left the warehouse                                                           |\n| shipped        | The order has ben shipped to the customer and is currently in transit                                                  |\n| completed      | The order has been received by the customer                                                                            |\n| return_pending | The customer has indicated that they would like to return the order, but it has not yet been received at the warehouse |\n| returned       | The order has been returned by the customer and received at the warehouse                                              |"}, "doc.dbt.__overview__": {"name": "__overview__", "resource_type": "doc", "package_name": "dbt", "path": "overview.md", "original_file_path": "docs/overview.md", "unique_id": "doc.dbt.__overview__", "block_contents": "### Welcome!\n\nWelcome to the auto-generated documentation for your dbt project!\n\n### Navigation\n\nYou can use the `Project` and `Database` navigation tabs on the left side of the window to explore the models\nin your project.\n\n#### Project Tab\nThe `Project` tab mirrors the directory structure of your dbt project. In this tab, you can see all of the\nmodels defined in your dbt project, as well as models imported from dbt packages.\n\n#### Database Tab\nThe `Database` tab also exposes your models, but in a format that looks more like a database explorer. This view\nshows relations (tables and views) grouped into database schemas. Note that ephemeral models are _not_ shown\nin this interface, as they do not exist in the database.\n\n### Graph Exploration\nYou can click the blue icon on the bottom-right corner of the page to view the lineage graph of your models.\n\nOn model pages, you'll see the immediate parents and children of the model you're exploring. By clicking the `Expand`\nbutton at the top-right of this lineage pane, you'll be able to see all of the models that are used to build,\nor are built from, the model you're exploring.\n\nOnce expanded, you'll be able to use the `--select` and `--exclude` model selection syntax to filter the\nmodels in the graph. For more information on model selection, check out the [dbt docs](https://docs.getdbt.com/docs/model-selection-syntax).\n\nNote that you can also right-click on models to interactively filter and explore the graph.\n\n---\n\n### More information\n\n- [What is dbt](https://docs.getdbt.com/docs/introduction)?\n- Read the [dbt viewpoint](https://docs.getdbt.com/docs/viewpoint)\n- [Installation](https://docs.getdbt.com/docs/installation)\n- Join the [dbt Community](https://www.getdbt.com/community/) for questions and discussion"}}, "exposures": {}, "metrics": {}, "selectors": {}, "disabled": {}, "parent_map": {"model.jaffle_shop.customers": ["model.jaffle_shop.stg_customers", "model.jaffle_shop.stg_orders", "model.jaffle_shop.stg_payments"], "model.jaffle_shop.orders": ["model.jaffle_shop.stg_orders", "model.jaffle_shop.stg_payments"], "model.jaffle_shop.stg_customers": ["seed.jaffle_shop.raw_customers"], "model.jaffle_shop.stg_payments": ["seed.jaffle_shop.raw_payments"], "model.jaffle_shop.stg_orders": ["seed.jaffle_shop.raw_orders"], "seed.jaffle_shop.raw_customers": [], "seed.jaffle_shop.raw_orders": [], "seed.jaffle_shop.raw_payments": [], "test.jaffle_shop.unique_customers_customer_id.c5af1ff4b1": ["model.jaffle_shop.customers"], "test.jaffle_shop.not_null_customers_customer_id.5c9bf9911d": ["model.jaffle_shop.customers"], "test.jaffle_shop.unique_orders_order_id.fed79b3a6e": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_order_id.cf6c17daed": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_customer_id.c5f02694af": ["model.jaffle_shop.orders"], "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2": ["model.jaffle_shop.customers", "model.jaffle_shop.orders"], "test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_amount.106140f9fd": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49": ["model.jaffle_shop.orders"], "test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a": ["model.jaffle_shop.orders"], "test.jaffle_shop.unique_stg_customers_customer_id.c7614daada": ["model.jaffle_shop.stg_customers"], "test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa": ["model.jaffle_shop.stg_customers"], "test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a": ["model.jaffle_shop.stg_orders"], "test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64": ["model.jaffle_shop.stg_orders"], "test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": ["model.jaffle_shop.stg_orders"], "test.jaffle_shop.unique_stg_payments_payment_id.3744510712": ["model.jaffle_shop.stg_payments"], "test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075": ["model.jaffle_shop.stg_payments"], "test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": ["model.jaffle_shop.stg_payments"]}, "child_map": {"model.jaffle_shop.customers": ["test.jaffle_shop.not_null_customers_customer_id.5c9bf9911d", "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2", "test.jaffle_shop.unique_customers_customer_id.c5af1ff4b1"], "model.jaffle_shop.orders": ["test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3", "test.jaffle_shop.not_null_orders_amount.106140f9fd", "test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49", "test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625", "test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59", "test.jaffle_shop.not_null_orders_customer_id.c5f02694af", "test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a", "test.jaffle_shop.not_null_orders_order_id.cf6c17daed", "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2", "test.jaffle_shop.unique_orders_order_id.fed79b3a6e"], "model.jaffle_shop.stg_customers": ["model.jaffle_shop.customers", "test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa", "test.jaffle_shop.unique_stg_customers_customer_id.c7614daada"], "model.jaffle_shop.stg_payments": ["model.jaffle_shop.customers", "model.jaffle_shop.orders", "test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278", "test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075", "test.jaffle_shop.unique_stg_payments_payment_id.3744510712"], "model.jaffle_shop.stg_orders": ["model.jaffle_shop.customers", "model.jaffle_shop.orders", "test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad", "test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64", "test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a"], "seed.jaffle_shop.raw_customers": ["model.jaffle_shop.stg_customers"], "seed.jaffle_shop.raw_orders": ["model.jaffle_shop.stg_orders"], "seed.jaffle_shop.raw_payments": ["model.jaffle_shop.stg_payments"], "test.jaffle_shop.unique_customers_customer_id.c5af1ff4b1": [], "test.jaffle_shop.not_null_customers_customer_id.5c9bf9911d": [], "test.jaffle_shop.unique_orders_order_id.fed79b3a6e": [], "test.jaffle_shop.not_null_orders_order_id.cf6c17daed": [], "test.jaffle_shop.not_null_orders_customer_id.c5f02694af": [], "test.jaffle_shop.relationships_orders_customer_id__customer_id__ref_customers_.c6ec7f58f2": [], "test.jaffle_shop.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": [], "test.jaffle_shop.not_null_orders_amount.106140f9fd": [], "test.jaffle_shop.not_null_orders_credit_card_amount.d3ca593b59": [], "test.jaffle_shop.not_null_orders_coupon_amount.ab90c90625": [], "test.jaffle_shop.not_null_orders_bank_transfer_amount.7743500c49": [], "test.jaffle_shop.not_null_orders_gift_card_amount.413a0d2d7a": [], "test.jaffle_shop.unique_stg_customers_customer_id.c7614daada": [], "test.jaffle_shop.not_null_stg_customers_customer_id.e2cfb1f9aa": [], "test.jaffle_shop.unique_stg_orders_order_id.e3b841c71a": [], "test.jaffle_shop.not_null_stg_orders_order_id.81cfe2fe64": [], "test.jaffle_shop.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": [], "test.jaffle_shop.unique_stg_payments_payment_id.3744510712": [], "test.jaffle_shop.not_null_stg_payments_payment_id.c19cc50075": [], "test.jaffle_shop.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": []}}
\ No newline at end of file
+{"metadata": {"dbt_schema_version": "https://schemas.getdbt.com/dbt/manifest/v11.json", "dbt_version": "1.7.3", "generated_at": "2024-01-31T18:05:25.193867Z", "invocation_id": "baf0db27-f48e-40a3-aa05-1b05b809ec5a", "env": {}, "project_name": "datafold_demo", "project_id": "e0814ec85ee7b1694571de4cad476003", "user_id": "f7f86073-1fa9-414c-9913-22c3648c2e32", "send_anonymous_usage_stats": true, "adapter_type": "duckdb"}, "nodes": {"model.datafold_demo.stg_customers": {"database": "jaffle_shop", "schema": "dev", "name": "stg_customers", "resource_type": "model", "package_name": "datafold_demo", "path": "staging/stg_customers.sql", "original_file_path": "models/staging/stg_customers.sql", "unique_id": "model.datafold_demo.stg_customers", "fqn": ["datafold_demo", "staging", "stg_customers"], "alias": "stg_customers", "checksum": {"name": "sha256", "checksum": "80e3223cd54387e11fa16cd0f4cbe15f8ff74dcd9900b93856b9e39416178c9d"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "access": "protected"}, "tags": [], "description": "", "columns": {"customer_id": {"name": "customer_id", "description": "", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": "datafold_demo://models/staging/schema.yml", "build_path": "target/run/datafold_demo/models/staging/stg_customers.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1706724325.78564, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_customers\"", "raw_code": "with source as (\n\n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_customers') }}\n\n),\n\nrenamed as (\n\n    select\n        id as customer_id,\n        first_name,\n        last_name\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [{"name": "raw_customers", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.datafold_demo.raw_customers"]}, "compiled_path": "target/compiled/datafold_demo/models/staging/stg_customers.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_customers\"\n\n),\n\nrenamed as (\n\n    select\n        id as customer_id,\n        first_name,\n        last_name\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": [], "contract": {"enforced": false, "alias_types": true, "checksum": null}, "access": "protected", "constraints": [], "version": null, "latest_version": null, "deprecation_date": null}, "model.datafold_demo.stg_payments": {"database": "jaffle_shop", "schema": "dev", "name": "stg_payments", "resource_type": "model", "package_name": "datafold_demo", "path": "staging/stg_payments.sql", "original_file_path": "models/staging/stg_payments.sql", "unique_id": "model.datafold_demo.stg_payments", "fqn": ["datafold_demo", "staging", "stg_payments"], "alias": "stg_payments", "checksum": {"name": "sha256", "checksum": "9c1ee3bfb10e07c2dfc325d55925da0e521887136d9051768cb8acf09dc86bda"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "access": "protected"}, "tags": [], "description": "", "columns": {"payment_id": {"name": "payment_id", "description": "", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "payment_method": {"name": "payment_method", "description": "", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": "datafold_demo://models/staging/schema.yml", "build_path": "target/run/datafold_demo/models/staging/stg_payments.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1706724325.7870321, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_payments\"", "raw_code": "with source as (\n    \n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_payments') }}\n\n),\n\nrenamed as (\n\n    select\n        id as payment_id,\n        order_id,\n        payment_method,\n\n        -- `amount` is currently stored in cents, so we convert it to dollars\n        amount / 100 as amount\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [{"name": "raw_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.datafold_demo.raw_payments"]}, "compiled_path": "target/compiled/datafold_demo/models/staging/stg_payments.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_payments\"\n\n),\n\nrenamed as (\n\n    select\n        id as payment_id,\n        order_id,\n        payment_method,\n\n        -- `amount` is currently stored in cents, so we convert it to dollars\n        amount / 100 as amount\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": [], "contract": {"enforced": false, "alias_types": true, "checksum": null}, "access": "protected", "constraints": [], "version": null, "latest_version": null, "deprecation_date": null}, "model.datafold_demo.stg_orders": {"database": "jaffle_shop", "schema": "dev", "name": "stg_orders", "resource_type": "model", "package_name": "datafold_demo", "path": "staging/stg_orders.sql", "original_file_path": "models/staging/stg_orders.sql", "unique_id": "model.datafold_demo.stg_orders", "fqn": ["datafold_demo", "staging", "stg_orders"], "alias": "stg_orders", "checksum": {"name": "sha256", "checksum": "f4f881cb09d2c4162200fc331d7401df6d1abd4fed492554a7db70dede347108"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "view", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "access": "protected"}, "tags": [], "description": "", "columns": {"order_id": {"name": "order_id", "description": "", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "status": {"name": "status", "description": "", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": "datafold_demo://models/staging/schema.yml", "build_path": "target/run/datafold_demo/models/staging/stg_orders.sql", "deferred": false, "unrendered_config": {"materialized": "view"}, "created_at": 1706724325.786328, "relation_name": "\"jaffle_shop\".\"dev\".\"stg_orders\"", "raw_code": "with source as (\n\n    {#-\n    Normally we would select from the table here, but we are using seeds to load\n    our data in this project\n    #}\n    select * from {{ ref('raw_orders') }}\n\n),\n\nrenamed as (\n\n    select\n        id as order_id,\n        user_id as customer_id,\n        order_date,\n        status\n\n    from source\n\n)\n\nselect * from renamed", "language": "sql", "refs": [{"name": "raw_orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["seed.datafold_demo.raw_orders"]}, "compiled_path": "target/compiled/datafold_demo/models/staging/stg_orders.sql", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_orders\"\n\n),\n\nrenamed as (\n\n    select\n        id as order_id,\n        user_id as customer_id,\n        order_date,\n        status\n\n    from source\n\n)\n\nselect * from renamed", "extra_ctes_injected": true, "extra_ctes": [], "contract": {"enforced": false, "alias_types": true, "checksum": null}, "access": "protected", "constraints": [], "version": null, "latest_version": null, "deprecation_date": null}, "model.datafold_demo.customers": {"database": "jaffle_shop", "schema": "dev", "name": "customers", "resource_type": "model", "package_name": "datafold_demo", "path": "core/customers.sql", "original_file_path": "models/core/customers.sql", "unique_id": "model.datafold_demo.customers", "fqn": ["datafold_demo", "core", "customers"], "alias": "customers", "checksum": {"name": "sha256", "checksum": "60bd72e33da43fff3a7e7609135c17cd4468bd22afec0735dd36018bfb5af30a"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "table", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "access": "protected"}, "tags": [], "description": "This table has basic information about a customer, as well as some derived facts based on a customer's orders", "columns": {"customer_id": {"name": "customer_id", "description": "This is a unique identifier for a customer", "meta": {"primary-key": true}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "first_name": {"name": "first_name", "description": "Customer's first name. PII.", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "last_name": {"name": "last_name", "description": "Customer's last name. PII.", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "first_order": {"name": "first_order", "description": "Date (UTC) of a customer's first order", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "most_recent_order": {"name": "most_recent_order", "description": "Date (UTC) of a customer's most recent order", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "number_of_orders": {"name": "number_of_orders", "description": "Count of the number of orders a customer has placed", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "total_order_amount": {"name": "total_order_amount", "description": "Total value (AUD) of a customer's orders", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": "datafold_demo://models/core/schema.yml", "build_path": "target/run/datafold_demo/models/core/customers.sql", "deferred": false, "unrendered_config": {"materialized": "table"}, "created_at": 1706724325.84845, "relation_name": "\"jaffle_shop\".\"dev\".\"customers\"", "raw_code": "with customers as (\n\n    select * from {{ ref('stg_customers') }}\n\n),\n\norders as (\n\n    select * from {{ ref('stg_orders') }}\n\n),\n\npayments as (\n\n    select * from {{ ref('stg_payments') }}\n\n),\n\ncustomer_orders as (\n\n        select\n        customer_id,\n\n        min(order_date) as first_order,\n        max(order_date) as most_recent_order,\n        count(order_id) as number_of_orders\n    from orders\n\n    group by customer_id\n\n),\n\ncustomer_payments as (\n\n    select\n        orders.customer_id,\n        sum(amount) as total_amount\n\n    from payments\n\n    left join orders on\n         payments.order_id = orders.order_id\n\n    group by orders.customer_id\n\n),\n\nfinal as (\n\n    select\n        customers.customer_id,\n        customers.first_name,\n        customers.last_name,\n        customer_orders.first_order,\n        customer_orders.most_recent_order,\n        customer_orders.number_of_orders,\n        customer_payments.total_amount as customer_lifetime_value\n\n    from customers\n\n    left join customer_orders\n        on customers.customer_id = customer_orders.customer_id\n\n    left join customer_payments\n        on  customers.customer_id = customer_payments.customer_id\n\n)\n\nselect * from final", "language": "sql", "refs": [{"name": "stg_customers", "package": null, "version": null}, {"name": "stg_orders", "package": null, "version": null}, {"name": "stg_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["model.datafold_demo.stg_customers", "model.datafold_demo.stg_orders", "model.datafold_demo.stg_payments"]}, "compiled_path": "target/compiled/datafold_demo/models/core/customers.sql", "compiled": true, "compiled_code": "with customers as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_customers\"\n\n),\n\norders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\ncustomer_orders as (\n\n        select\n        customer_id,\n\n        min(order_date) as first_order,\n        max(order_date) as most_recent_order,\n        count(order_id) as number_of_orders\n    from orders\n\n    group by customer_id\n\n),\n\ncustomer_payments as (\n\n    select\n        orders.customer_id,\n        sum(amount) as total_amount\n\n    from payments\n\n    left join orders on\n         payments.order_id = orders.order_id\n\n    group by orders.customer_id\n\n),\n\nfinal as (\n\n    select\n        customers.customer_id,\n        customers.first_name,\n        customers.last_name,\n        customer_orders.first_order,\n        customer_orders.most_recent_order,\n        customer_orders.number_of_orders,\n        customer_payments.total_amount as customer_lifetime_value\n\n    from customers\n\n    left join customer_orders\n        on customers.customer_id = customer_orders.customer_id\n\n    left join customer_payments\n        on  customers.customer_id = customer_payments.customer_id\n\n)\n\nselect * from final", "extra_ctes_injected": true, "extra_ctes": [], "contract": {"enforced": false, "alias_types": true, "checksum": null}, "access": "protected", "constraints": [], "version": null, "latest_version": null, "deprecation_date": null}, "model.datafold_demo.orders": {"database": "jaffle_shop", "schema": "dev", "name": "orders", "resource_type": "model", "package_name": "datafold_demo", "path": "core/orders.sql", "original_file_path": "models/core/orders.sql", "unique_id": "model.datafold_demo.orders", "fqn": ["datafold_demo", "core", "orders"], "alias": "orders", "checksum": {"name": "sha256", "checksum": "a81ee7b57492458b7c79e2dd9cc171b62be82d197123cb56c60bcea74d9e16a9"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {"datafold": {"datadiff": {"filter": "amount >= 0", "include_columns": ["order_id", "customer_id", "order_date", "amount", "credit_card_amount", "coupon_amount", "bank_transfer_amount", "gift_card_amount"], "exclude_columns": ["new_column"]}}}, "group": null, "materialized": "table", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "access": "protected"}, "tags": [], "description": "This table has basic information about orders, as well as some derived facts based on payments", "columns": {"order_id": {"name": "order_id", "description": "This is a unique identifier for an order", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "customer_id": {"name": "customer_id", "description": "Foreign key to the customers table", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "order_date": {"name": "order_date", "description": "Date (UTC) that the order was placed", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "status": {"name": "status", "description": "Orders can be one of the following statuses:\n\n| status         | description                                                                                                            |\n|----------------|------------------------------------------------------------------------------------------------------------------------|\n| placed         | The order has been placed but has not yet left the warehouse                                                           |\n| shipped        | The order has ben shipped to the customer and is currently in transit                                                  |\n| completed      | The order has been received by the customer                                                                            |\n| return_pending | The customer has indicated that they would like to return the order, but it has not yet been received at the warehouse |\n| returned       | The order has been returned by the customer and received at the warehouse                                              |", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "amount": {"name": "amount", "description": "Total amount (AUD) of the order", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "credit_card_amount": {"name": "credit_card_amount", "description": "Amount of the order (AUD) paid for by credit card", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "coupon_amount": {"name": "coupon_amount", "description": "Amount of the order (AUD) paid for by coupon", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "bank_transfer_amount": {"name": "bank_transfer_amount", "description": "Amount of the order (AUD) paid for by bank transfer", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}, "gift_card_amount": {"name": "gift_card_amount", "description": "Amount of the order (AUD) paid for by gift card", "meta": {}, "data_type": null, "constraints": [], "quote": null, "tags": []}}, "meta": {"datafold": {"datadiff": {"filter": "amount >= 0", "include_columns": ["order_id", "customer_id", "order_date", "amount", "credit_card_amount", "coupon_amount", "bank_transfer_amount", "gift_card_amount"], "exclude_columns": ["new_column"]}}}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": "datafold_demo://models/core/schema.yml", "build_path": "target/run/datafold_demo/models/core/orders.sql", "deferred": false, "unrendered_config": {"materialized": "table", "meta": {"datafold": {"datadiff": {"filter": "amount >= 0", "include_columns": ["order_id", "customer_id", "order_date", "amount", "credit_card_amount", "coupon_amount", "bank_transfer_amount", "gift_card_amount"], "exclude_columns": ["new_column"]}}}}, "created_at": 1706724325.851211, "relation_name": "\"jaffle_shop\".\"dev\".\"orders\"", "raw_code": "{% set payment_methods = ['credit_card', 'coupon', 'bank_transfer', 'gift_card'] %}\n\nwith orders as (\n\n    select * from {{ ref('stg_orders') }}\n\n),\n\npayments as (\n\n    select * from {{ ref('stg_payments') }}\n\n),\n\norder_payments as (\n\n    select\n        order_id,\n\n        {% for payment_method in payment_methods -%}\n        sum(case when payment_method = '{{ payment_method }}' then amount else 0 end) as {{ payment_method }}_amount,\n        {% endfor -%}\n\n        sum(amount) as total_amount\n\n    from payments\n\n    group by order_id\n\n),\n\nfinal as (\n\n    select\n        orders.order_id+1 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        {# orders.status, #}\n        1 as new_column,\n\n        {% for payment_method in payment_methods -%}\n\n        order_payments.{{ payment_method }}_amount,\n\n        {% endfor -%}\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n),\n\nfinal2 as (\n\n    select\n        orders.order_id+2 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        {# orders.status, #}\n        1 as new_column,\n\n        {% for payment_method in payment_methods -%}\n\n        order_payments.{{ payment_method }}_amount,\n\n        {% endfor -%}\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n)\n\n(select * from final limit 10)\nunion all\n(select * from final2 where order_id not in (select order_id from final) limit 10)", "language": "sql", "refs": [{"name": "stg_orders", "package": null, "version": null}, {"name": "stg_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": [], "nodes": ["model.datafold_demo.stg_orders", "model.datafold_demo.stg_payments"]}, "compiled_path": "target/compiled/datafold_demo/models/core/orders.sql", "compiled": true, "compiled_code": "\n\nwith orders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\norder_payments as (\n\n    select\n        order_id,\n\n        sum(case when payment_method = 'credit_card' then amount else 0 end) as credit_card_amount,\n        sum(case when payment_method = 'coupon' then amount else 0 end) as coupon_amount,\n        sum(case when payment_method = 'bank_transfer' then amount else 0 end) as bank_transfer_amount,\n        sum(case when payment_method = 'gift_card' then amount else 0 end) as gift_card_amount,\n        sum(amount) as total_amount\n\n    from payments\n\n    group by order_id\n\n),\n\nfinal as (\n\n    select\n        orders.order_id+1 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        \n        1 as new_column,\n\n        order_payments.credit_card_amount,\n\n        order_payments.coupon_amount,\n\n        order_payments.bank_transfer_amount,\n\n        order_payments.gift_card_amount,\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n),\n\nfinal2 as (\n\n    select\n        orders.order_id+2 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        \n        1 as new_column,\n\n        order_payments.credit_card_amount,\n\n        order_payments.coupon_amount,\n\n        order_payments.bank_transfer_amount,\n\n        order_payments.gift_card_amount,\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n)\n\n(select * from final limit 10)\nunion all\n(select * from final2 where order_id not in (select order_id from final) limit 10)", "extra_ctes_injected": true, "extra_ctes": [], "contract": {"enforced": false, "alias_types": true, "checksum": null}, "access": "protected", "constraints": [], "version": null, "latest_version": null, "deprecation_date": null}, "seed.datafold_demo.raw_customers": {"database": "jaffle_shop", "schema": "dev", "name": "raw_customers", "resource_type": "seed", "package_name": "datafold_demo", "path": "raw_customers.csv", "original_file_path": "seeds/raw_customers.csv", "unique_id": "seed.datafold_demo.raw_customers", "fqn": ["datafold_demo", "raw_customers"], "alias": "raw_customers", "checksum": {"name": "sha256", "checksum": "357d173dda65a741ad97d6683502286cc2655bb396ab5f4dfad12b8c39bd2a63"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "delimiter": ",", "quote_columns": null, "fast": true}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"fast": true}, "created_at": 1706724325.746119, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_customers\"", "raw_code": "", "root_path": "/Users/sung/Desktop/data-diff/data_diff_demo", "depends_on": {"macros": []}}, "seed.datafold_demo.raw_orders": {"database": "jaffle_shop", "schema": "dev", "name": "raw_orders", "resource_type": "seed", "package_name": "datafold_demo", "path": "raw_orders.csv", "original_file_path": "seeds/raw_orders.csv", "unique_id": "seed.datafold_demo.raw_orders", "fqn": ["datafold_demo", "raw_orders"], "alias": "raw_orders", "checksum": {"name": "sha256", "checksum": "10ef49f6f03495b970b186248cc1123bc3ecf931f4e8bcafe65730089584d2a0"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "delimiter": ",", "quote_columns": null, "fast": true}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"fast": true}, "created_at": 1706724325.747665, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_orders\"", "raw_code": "", "root_path": "/Users/sung/Desktop/data-diff/data_diff_demo", "depends_on": {"macros": []}}, "seed.datafold_demo.raw_payments": {"database": "jaffle_shop", "schema": "dev", "name": "raw_payments", "resource_type": "seed", "package_name": "datafold_demo", "path": "raw_payments.csv", "original_file_path": "seeds/raw_payments.csv", "unique_id": "seed.datafold_demo.raw_payments", "fqn": ["datafold_demo", "raw_payments"], "alias": "raw_payments", "checksum": {"name": "sha256", "checksum": "6de0626a8db9c1750eefd1b2e17fac4c2a4b9f778eb50532d8b377b90de395e6"}, "config": {"enabled": true, "alias": null, "schema": null, "database": null, "tags": [], "meta": {}, "group": null, "materialized": "seed", "incremental_strategy": null, "persist_docs": {}, "post-hook": [], "pre-hook": [], "quoting": {}, "column_types": {}, "full_refresh": null, "unique_key": null, "on_schema_change": "ignore", "on_configuration_change": "apply", "grants": {}, "packages": [], "docs": {"show": true, "node_color": null}, "contract": {"enforced": false, "alias_types": true}, "delimiter": ",", "quote_columns": null, "fast": true}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"fast": true}, "created_at": 1706724325.749057, "relation_name": "\"jaffle_shop\".\"dev\".\"raw_payments\"", "raw_code": "", "root_path": "/Users/sung/Desktop/data-diff/data_diff_demo", "depends_on": {"macros": []}}, "test.datafold_demo.unique_stg_customers_customer_id.c7614daada": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('stg_customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_customers_customer_id", "resource_type": "test", "package_name": "datafold_demo", "path": "unique_stg_customers_customer_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.unique_stg_customers_customer_id.c7614daada", "fqn": ["datafold_demo", "staging", "unique_stg_customers_customer_id"], "alias": "unique_stg_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.828681, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_customers", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.datafold_demo.stg_customers"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "customer_id", "file_key_name": "models.stg_customers", "attached_node": "model.datafold_demo.stg_customers"}, "test.datafold_demo.not_null_stg_customers_customer_id.e2cfb1f9aa": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('stg_customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_customers_customer_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_stg_customers_customer_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.not_null_stg_customers_customer_id.e2cfb1f9aa", "fqn": ["datafold_demo", "staging", "not_null_stg_customers_customer_id"], "alias": "not_null_stg_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.8301098, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_customers", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.stg_customers"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "customer_id", "file_key_name": "models.stg_customers", "attached_node": "model.datafold_demo.stg_customers"}, "test.datafold_demo.unique_stg_orders_order_id.e3b841c71a": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_orders_order_id", "resource_type": "test", "package_name": "datafold_demo", "path": "unique_stg_orders_order_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.unique_stg_orders_order_id.e3b841c71a", "fqn": ["datafold_demo", "staging", "unique_stg_orders_order_id"], "alias": "unique_stg_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.83131, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.datafold_demo.stg_orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "order_id", "file_key_name": "models.stg_orders", "attached_node": "model.datafold_demo.stg_orders"}, "test.datafold_demo.not_null_stg_orders_order_id.81cfe2fe64": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_orders_order_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_stg_orders_order_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.not_null_stg_orders_order_id.81cfe2fe64", "fqn": ["datafold_demo", "staging", "not_null_stg_orders_order_id"], "alias": "not_null_stg_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.832438, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.stg_orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "order_id", "file_key_name": "models.stg_orders", "attached_node": "model.datafold_demo.stg_orders"}, "test.datafold_demo.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["placed", "shipped", "completed", "return_pending", "returned"], "column_name": "status", "model": "{{ get_where_subquery(ref('stg_orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned", "resource_type": "test", "package_name": "datafold_demo", "path": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad", "fqn": ["datafold_demo", "staging", "accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned"], "alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58"}, "created_at": 1706724325.833625, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_stg_orders_4f514bf94b77b7ea437830eec4421c58\") }}", "language": "sql", "refs": [{"name": "stg_orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.datafold_demo.stg_orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "status", "file_key_name": "models.stg_orders", "attached_node": "model.datafold_demo.stg_orders"}, "test.datafold_demo.unique_stg_payments_payment_id.3744510712": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "payment_id", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_stg_payments_payment_id", "resource_type": "test", "package_name": "datafold_demo", "path": "unique_stg_payments_payment_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.unique_stg_payments_payment_id.3744510712", "fqn": ["datafold_demo", "staging", "unique_stg_payments_payment_id"], "alias": "unique_stg_payments_payment_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.841217, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.datafold_demo.stg_payments"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "payment_id", "file_key_name": "models.stg_payments", "attached_node": "model.datafold_demo.stg_payments"}, "test.datafold_demo.not_null_stg_payments_payment_id.c19cc50075": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "payment_id", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_stg_payments_payment_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_stg_payments_payment_id.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.not_null_stg_payments_payment_id.c19cc50075", "fqn": ["datafold_demo", "staging", "not_null_stg_payments_payment_id"], "alias": "not_null_stg_payments_payment_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.842358, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "stg_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.stg_payments"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "payment_id", "file_key_name": "models.stg_payments", "attached_node": "model.datafold_demo.stg_payments"}, "test.datafold_demo.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["credit_card", "coupon", "bank_transfer", "gift_card"], "column_name": "payment_method", "model": "{{ get_where_subquery(ref('stg_payments')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card", "resource_type": "test", "package_name": "datafold_demo", "path": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef.sql", "original_file_path": "models/staging/schema.yml", "unique_id": "test.datafold_demo.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278", "fqn": ["datafold_demo", "staging", "accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card"], "alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef"}, "created_at": 1706724325.8435452, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_stg_payments_c7909fb19b1f0177c2bf99c7912f06ef\") }}", "language": "sql", "refs": [{"name": "stg_payments", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.datafold_demo.stg_payments"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "payment_method", "file_key_name": "models.stg_payments", "attached_node": "model.datafold_demo.stg_payments"}, "test.datafold_demo.unique_customers_customer_id.c5af1ff4b1": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_customers_customer_id", "resource_type": "test", "package_name": "datafold_demo", "path": "unique_customers_customer_id.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.unique_customers_customer_id.c5af1ff4b1", "fqn": ["datafold_demo", "core", "unique_customers_customer_id"], "alias": "unique_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.851627, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "customers", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.datafold_demo.customers"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "customer_id", "file_key_name": "models.customers", "attached_node": "model.datafold_demo.customers"}, "test.datafold_demo.not_null_customers_customer_id.5c9bf9911d": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('customers')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_customers_customer_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_customers_customer_id.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_customers_customer_id.5c9bf9911d", "fqn": ["datafold_demo", "core", "not_null_customers_customer_id"], "alias": "not_null_customers_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.852818, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "customers", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.customers"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "customer_id", "file_key_name": "models.customers", "attached_node": "model.datafold_demo.customers"}, "test.datafold_demo.unique_orders_order_id.fed79b3a6e": {"test_metadata": {"name": "unique", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "unique_orders_order_id", "resource_type": "test", "package_name": "datafold_demo", "path": "unique_orders_order_id.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.unique_orders_order_id.fed79b3a6e", "fqn": ["datafold_demo", "core", "unique_orders_order_id"], "alias": "unique_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.853958, "relation_name": null, "raw_code": "{{ test_unique(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_unique"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "order_id", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_order_id.cf6c17daed": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "order_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_order_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_order_id.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_order_id.cf6c17daed", "fqn": ["datafold_demo", "core", "not_null_orders_order_id"], "alias": "not_null_orders_order_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.855113, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "order_id", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_customer_id.c5f02694af": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "customer_id", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_customer_id", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_customer_id.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_customer_id.c5f02694af", "fqn": ["datafold_demo", "core", "not_null_orders_customer_id"], "alias": "not_null_orders_customer_id", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.856253, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "customer_id", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": {"test_metadata": {"name": "accepted_values", "kwargs": {"values": ["placed", "shipped", "completed", "return_pending", "returned"], "column_name": "status", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "accepted_values_orders_status__placed__shipped__completed__return_pending__returned", "resource_type": "test", "package_name": "datafold_demo", "path": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3", "fqn": ["datafold_demo", "core", "accepted_values_orders_status__placed__shipped__completed__return_pending__returned"], "alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758", "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {"alias": "accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758"}, "created_at": 1706724325.857507, "relation_name": null, "raw_code": "{{ test_accepted_values(**_dbt_generic_test_kwargs) }}{{ config(alias=\"accepted_values_orders_1ce6ab157c285f7cd2ac656013faf758\") }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_accepted_values", "macro.dbt.get_where_subquery"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "status", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_amount.106140f9fd": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_amount", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_amount.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_amount.106140f9fd", "fqn": ["datafold_demo", "core", "not_null_orders_amount"], "alias": "not_null_orders_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.86013, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "amount", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_credit_card_amount.d3ca593b59": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "credit_card_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_credit_card_amount", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_credit_card_amount.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_credit_card_amount.d3ca593b59", "fqn": ["datafold_demo", "core", "not_null_orders_credit_card_amount"], "alias": "not_null_orders_credit_card_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.861248, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "credit_card_amount", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_coupon_amount.ab90c90625": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "coupon_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_coupon_amount", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_coupon_amount.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_coupon_amount.ab90c90625", "fqn": ["datafold_demo", "core", "not_null_orders_coupon_amount"], "alias": "not_null_orders_coupon_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.8625238, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "coupon_amount", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_bank_transfer_amount.7743500c49": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "bank_transfer_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_bank_transfer_amount", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_bank_transfer_amount.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_bank_transfer_amount.7743500c49", "fqn": ["datafold_demo", "core", "not_null_orders_bank_transfer_amount"], "alias": "not_null_orders_bank_transfer_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.863639, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "bank_transfer_amount", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}, "test.datafold_demo.not_null_orders_gift_card_amount.413a0d2d7a": {"test_metadata": {"name": "not_null", "kwargs": {"column_name": "gift_card_amount", "model": "{{ get_where_subquery(ref('orders')) }}"}, "namespace": null}, "database": "jaffle_shop", "schema": "dev_dbt_test__audit", "name": "not_null_orders_gift_card_amount", "resource_type": "test", "package_name": "datafold_demo", "path": "not_null_orders_gift_card_amount.sql", "original_file_path": "models/core/schema.yml", "unique_id": "test.datafold_demo.not_null_orders_gift_card_amount.413a0d2d7a", "fqn": ["datafold_demo", "core", "not_null_orders_gift_card_amount"], "alias": "not_null_orders_gift_card_amount", "checksum": {"name": "none", "checksum": ""}, "config": {"enabled": true, "alias": null, "schema": "dbt_test__audit", "database": null, "tags": [], "meta": {}, "group": null, "materialized": "test", "severity": "ERROR", "store_failures": null, "store_failures_as": null, "where": null, "limit": null, "fail_calc": "count(*)", "warn_if": "!= 0", "error_if": "!= 0"}, "tags": [], "description": "", "columns": {}, "meta": {}, "group": null, "docs": {"show": true, "node_color": null}, "patch_path": null, "build_path": null, "deferred": false, "unrendered_config": {}, "created_at": 1706724325.864759, "relation_name": null, "raw_code": "{{ test_not_null(**_dbt_generic_test_kwargs) }}", "language": "sql", "refs": [{"name": "orders", "package": null, "version": null}], "sources": [], "metrics": [], "depends_on": {"macros": ["macro.dbt.test_not_null"], "nodes": ["model.datafold_demo.orders"]}, "compiled_path": null, "contract": {"enforced": false, "alias_types": true, "checksum": null}, "column_name": "gift_card_amount", "file_key_name": "models.orders", "attached_node": "model.datafold_demo.orders"}}, "sources": {}, "macros": {"macro.dbt_duckdb.duckdb__get_binding_char": {"name": "duckdb__get_binding_char", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_binding_char", "macro_sql": "{% macro duckdb__get_binding_char() %}\n  {{ return(adapter.get_binding_char()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2156742, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_batch_size": {"name": "duckdb__get_batch_size", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_batch_size", "macro_sql": "{% macro duckdb__get_batch_size() %}\n  {{ return(10000) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.215832, "supported_languages": null}, "macro.dbt_duckdb.duckdb__load_csv_rows": {"name": "duckdb__load_csv_rows", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/seed.sql", "original_file_path": "macros/seed.sql", "unique_id": "macro.dbt_duckdb.duckdb__load_csv_rows", "macro_sql": "{% macro duckdb__load_csv_rows(model, agate_table) %}\n    {% if config.get('fast', true) %}\n        {% set seed_file_path = adapter.get_seed_file_path(model) %}\n        {% set delimiter = config.get('delimiter', ',') %}\n        {% set sql %}\n          COPY {{ this.render() }} FROM '{{ seed_file_path }}' (FORMAT CSV, HEADER TRUE, DELIMITER '{{ delimiter }}')\n        {% endset %}\n        {% do adapter.add_query(sql, abridge_sql_log=True) %}\n        {{ return(sql) }}\n    {% endif %}\n\n    {% set batch_size = get_batch_size() %}\n    {% set agate_table = adapter.convert_datetimes_to_strs(agate_table) %}\n    {% set cols_sql = get_seed_column_quoted_csv(model, agate_table.column_names) %}\n    {% set bindings = [] %}\n\n    {% set statements = [] %}\n\n    {% for chunk in agate_table.rows | batch(batch_size) %}\n        {% set bindings = [] %}\n\n        {% for row in chunk %}\n            {% do bindings.extend(row) %}\n        {% endfor %}\n\n        {% set sql %}\n            insert into {{ this.render() }} ({{ cols_sql }}) values\n            {% for row in chunk -%}\n                ({%- for column in agate_table.column_names -%}\n                    {{ get_binding_char() }}\n                    {%- if not loop.last%},{%- endif %}\n                {%- endfor -%})\n                {%- if not loop.last%},{%- endif %}\n            {%- endfor %}\n        {% endset %}\n\n        {% do adapter.add_query(sql, bindings=bindings, abridge_sql_log=True) %}\n\n        {% if loop.index0 == 0 %}\n            {% do statements.append(sql) %}\n        {% endif %}\n    {% endfor %}\n\n    {# Return SQL so we can render it out into the compiled files #}\n    {{ return(statements[0]) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_batch_size", "macro.dbt.get_seed_column_quoted_csv", "macro.dbt.get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.217742, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_merge_sql": {"name": "duckdb__snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/snapshot_helper.sql", "original_file_path": "macros/snapshot_helper.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_merge_sql", "macro_sql": "{% macro duckdb__snapshot_merge_sql(target, source, insert_cols) -%}\n    {%- set insert_cols_csv = insert_cols | join(', ') -%}\n\n    update {{ target }} as DBT_INTERNAL_TARGET\n    set dbt_valid_to = DBT_INTERNAL_SOURCE.dbt_valid_to\n    from {{ source }} as DBT_INTERNAL_SOURCE\n    where DBT_INTERNAL_SOURCE.dbt_scd_id::text = DBT_INTERNAL_TARGET.dbt_scd_id::text\n      and DBT_INTERNAL_SOURCE.dbt_change_type::text in ('update'::text, 'delete'::text)\n      and DBT_INTERNAL_TARGET.dbt_valid_to is null;\n\n    insert into {{ target }} ({{ insert_cols_csv }})\n    select {% for column in insert_cols -%}\n        DBT_INTERNAL_SOURCE.{{ column }} {%- if not loop.last %}, {%- endif %}\n    {%- endfor %}\n    from {{ source }} as DBT_INTERNAL_SOURCE\n    where DBT_INTERNAL_SOURCE.dbt_change_type::text = 'insert'::text;\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.218645, "supported_languages": null}, "macro.dbt_duckdb.build_snapshot_staging_table": {"name": "build_snapshot_staging_table", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/snapshot_helper.sql", "original_file_path": "macros/snapshot_helper.sql", "unique_id": "macro.dbt_duckdb.build_snapshot_staging_table", "macro_sql": "{% macro build_snapshot_staging_table(strategy, sql, target_relation) %}\n    {% set temp_relation = make_temp_relation(target_relation) %}\n\n    {% set select = snapshot_staging_table(strategy, sql, target_relation) %}\n\n    {% call statement('build_snapshot_staging_relation') %}\n        {{ create_table_as(False, temp_relation, select) }}\n    {% endcall %}\n\n    {% do return(temp_relation) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_temp_relation", "macro.dbt.snapshot_staging_table", "macro.dbt.statement", "macro.dbt.create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.219084, "supported_languages": null}, "macro.dbt_duckdb.duckdb__post_snapshot": {"name": "duckdb__post_snapshot", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/snapshot_helper.sql", "original_file_path": "macros/snapshot_helper.sql", "unique_id": "macro.dbt_duckdb.duckdb__post_snapshot", "macro_sql": "{% macro duckdb__post_snapshot(staging_relation) %}\n    {% do return(drop_relation(staging_relation)) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.drop_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.219243, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_catalog": {"name": "duckdb__get_catalog", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/catalog.sql", "original_file_path": "macros/catalog.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_catalog", "macro_sql": "{% macro duckdb__get_catalog(information_schema, schemas) -%}\n  {%- call statement('catalog', fetch_result=True) -%}\n    select\n        '{{ database }}' as table_database,\n        t.table_schema,\n        t.table_name,\n        t.table_type,\n        '' as table_comment,\n        c.column_name,\n        c.ordinal_position as column_index,\n        c.data_type column_type,\n        '' as column_comment,\n        '' as table_owner\n    FROM information_schema.tables t JOIN information_schema.columns c ON t.table_schema = c.table_schema AND t.table_name = c.table_name\n    WHERE (\n        {%- for schema in schemas -%}\n          upper(t.table_schema) = upper('{{ schema }}'){%- if not loop.last %} or {% endif -%}\n        {%- endfor -%}\n    )\n    AND t.table_type IN ('BASE TABLE', 'VIEW')\n    ORDER BY\n        t.table_schema,\n        t.table_name,\n        c.ordinal_position\n  {%- endcall -%}\n  {{ return(load_result('catalog').table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.219906, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_schema": {"name": "duckdb__create_schema", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_schema", "macro_sql": "{% macro duckdb__create_schema(relation) -%}\n  {%- call statement('create_schema') -%}\n    create schema if not exists {{ relation.without_identifier() }}\n  {%- endcall -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2280838, "supported_languages": null}, "macro.dbt_duckdb.duckdb__drop_schema": {"name": "duckdb__drop_schema", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__drop_schema", "macro_sql": "{% macro duckdb__drop_schema(relation) -%}\n  {%- call statement('drop_schema') -%}\n    drop schema if exists {{ relation.without_identifier() }} cascade\n  {%- endcall -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.22829, "supported_languages": null}, "macro.dbt_duckdb.duckdb__list_schemas": {"name": "duckdb__list_schemas", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__list_schemas", "macro_sql": "{% macro duckdb__list_schemas(database) -%}\n  {% set sql %}\n    select schema_name\n    from system.information_schema.schemata\n    {% if database is not none %}\n    where catalog_name = '{{ database }}'\n    {% endif %}\n  {% endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.228587, "supported_languages": null}, "macro.dbt_duckdb.duckdb__check_schema_exists": {"name": "duckdb__check_schema_exists", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__check_schema_exists", "macro_sql": "{% macro duckdb__check_schema_exists(information_schema, schema) -%}\n  {% set sql -%}\n        select count(*)\n        from system.information_schema.schemata\n        where schema_name = '{{ schema }}'\n        and catalog_name = '{{ information_schema.database }}'\n  {%- endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.228841, "supported_languages": null}, "macro.dbt_duckdb.get_column_names": {"name": "get_column_names", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.get_column_names", "macro_sql": "{% macro get_column_names() %}\n  {# loop through user_provided_columns to get column names #}\n    {%- set user_provided_columns = model['columns'] -%}\n    (\n    {% for i in user_provided_columns %}\n      {% set col = user_provided_columns[i] %}\n      {{ col['name'] }} {{ \",\" if not loop.last }}\n    {% endfor %}\n  )\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2292428, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_table_as": {"name": "duckdb__create_table_as", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_table_as", "macro_sql": "{% macro duckdb__create_table_as(temporary, relation, compiled_code, language='sql') -%}\n  {%- if language == 'sql' -%}\n    {% set contract_config = config.get('contract') %}\n    {% if contract_config.enforced %}\n      {{ get_assert_columns_equivalent(compiled_code) }}\n    {% endif %}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {{ sql_header if sql_header is not none }}\n\n    create {% if temporary: -%}temporary{%- endif %} table\n      {{ relation.include(database=(not temporary), schema=(not temporary)) }}\n  {% if contract_config.enforced and not temporary %}\n    {#-- DuckDB doesnt support constraints on temp tables --#}\n    {{ get_table_columns_and_constraints() }} ;\n    insert into {{ relation }} {{ get_column_names() }} (\n      {{ get_select_subquery(compiled_code) }}\n    );\n  {% else %}\n    as (\n      {{ compiled_code }}\n    );\n  {% endif %}\n  {%- elif language == 'python' -%}\n    {{ py_write_table(temporary=temporary, relation=relation, compiled_code=compiled_code) }}\n  {%- else -%}\n      {% do exceptions.raise_compiler_error(\"duckdb__create_table_as macro didn't get supported language, it got %s\" % language) %}\n  {%- endif -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_assert_columns_equivalent", "macro.dbt.get_table_columns_and_constraints", "macro.dbt_duckdb.get_column_names", "macro.dbt.get_select_subquery", "macro.dbt_duckdb.py_write_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.230325, "supported_languages": null}, "macro.dbt_duckdb.py_write_table": {"name": "py_write_table", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.py_write_table", "macro_sql": "{% macro py_write_table(temporary, relation, compiled_code) -%}\n{{ compiled_code }}\n\ndef materialize(df, con):\n    try:\n        import pyarrow\n        pyarrow_available = True\n    except ImportError:\n        pyarrow_available = False\n    finally:\n        if pyarrow_available and isinstance(df, pyarrow.Table):\n            # https://github.com/duckdb/duckdb/issues/6584\n            import pyarrow.dataset\n    con.execute('create table {{ relation }} as select * from df')\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.230502, "supported_languages": null}, "macro.dbt_duckdb.duckdb__create_view_as": {"name": "duckdb__create_view_as", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__create_view_as", "macro_sql": "{% macro duckdb__create_view_as(relation, sql) -%}\n  {% set contract_config = config.get('contract') %}\n  {% if contract_config.enforced %}\n    {{ get_assert_columns_equivalent(sql) }}\n  {%- endif %}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n  create view {{ relation }} as (\n    {{ sql }}\n  );\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_assert_columns_equivalent"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.230922, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_columns_in_relation": {"name": "duckdb__get_columns_in_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_columns_in_relation", "macro_sql": "{% macro duckdb__get_columns_in_relation(relation) -%}\n  {% call statement('get_columns_in_relation', fetch_result=True) %}\n      select\n          column_name,\n          data_type,\n          character_maximum_length,\n          numeric_precision,\n          numeric_scale\n\n      from system.information_schema.columns\n      where table_name = '{{ relation.identifier }}'\n      {% if relation.schema %}\n      and table_schema = '{{ relation.schema }}'\n      {% endif %}\n      {% if relation.database %}\n      and table_catalog = '{{ relation.database }}'\n      {% endif %}\n      order by ordinal_position\n\n  {% endcall %}\n  {% set table = load_result('get_columns_in_relation').table %}\n  {{ return(sql_convert_columns_in_relation(table)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.sql_convert_columns_in_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2314408, "supported_languages": null}, "macro.dbt_duckdb.duckdb__list_relations_without_caching": {"name": "duckdb__list_relations_without_caching", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__list_relations_without_caching", "macro_sql": "{% macro duckdb__list_relations_without_caching(schema_relation) %}\n  {% call statement('list_relations_without_caching', fetch_result=True) -%}\n    select\n      '{{ schema_relation.database }}' as database,\n      table_name as name,\n      table_schema as schema,\n      CASE table_type\n        WHEN 'BASE TABLE' THEN 'table'\n        WHEN 'VIEW' THEN 'view'\n        WHEN 'LOCAL TEMPORARY' THEN 'table'\n        END as type\n    from system.information_schema.tables\n    where table_schema = '{{ schema_relation.schema }}'\n    and table_catalog = '{{ schema_relation.database }}'\n  {% endcall %}\n  {{ return(load_result('list_relations_without_caching').table) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.231773, "supported_languages": null}, "macro.dbt_duckdb.duckdb__drop_relation": {"name": "duckdb__drop_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__drop_relation", "macro_sql": "{% macro duckdb__drop_relation(relation) -%}\n  {% call statement('drop_relation', auto_begin=False) -%}\n    drop {{ relation.type }} if exists {{ relation }} cascade\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.231991, "supported_languages": null}, "macro.dbt_duckdb.duckdb__rename_relation": {"name": "duckdb__rename_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__rename_relation", "macro_sql": "{% macro duckdb__rename_relation(from_relation, to_relation) -%}\n  {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}\n  {% call statement('rename_relation') -%}\n    alter {{ to_relation.type }} {{ from_relation }} rename to {{ target_name }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.232312, "supported_languages": null}, "macro.dbt_duckdb.duckdb__make_temp_relation": {"name": "duckdb__make_temp_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__make_temp_relation", "macro_sql": "{% macro duckdb__make_temp_relation(base_relation, suffix) %}\n    {% set tmp_identifier = base_relation.identifier ~ suffix ~ py_current_timestring() %}\n    {% do return(base_relation.incorporate(\n                                  path={\n                                    \"identifier\": tmp_identifier,\n                                    \"schema\": none,\n                                    \"database\": none\n                                  })) -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.py_current_timestring"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.232762, "supported_languages": null}, "macro.dbt_duckdb.duckdb__current_timestamp": {"name": "duckdb__current_timestamp", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__current_timestamp", "macro_sql": "{% macro duckdb__current_timestamp() -%}\n  now()\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.232842, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_string_as_time": {"name": "duckdb__snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_string_as_time", "macro_sql": "{% macro duckdb__snapshot_string_as_time(timestamp) -%}\n    {%- set result = \"'\" ~ timestamp ~ \"'::timestamp\" -%}\n    {{ return(result) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2330172, "supported_languages": null}, "macro.dbt_duckdb.duckdb__snapshot_get_time": {"name": "duckdb__snapshot_get_time", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__snapshot_get_time", "macro_sql": "{% macro duckdb__snapshot_get_time() -%}\n  {{ current_timestamp() }}::timestamp\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.233113, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_incremental_default_sql": {"name": "duckdb__get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_incremental_default_sql", "macro_sql": "{% macro duckdb__get_incremental_default_sql(arg_dict) %}\n  {% do return(get_incremental_delete_insert_sql(arg_dict)) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_incremental_delete_insert_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.233261, "supported_languages": null}, "macro.dbt_duckdb.location_exists": {"name": "location_exists", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.location_exists", "macro_sql": "{% macro location_exists(location) -%}\n  {% do return(adapter.location_exists(location)) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.233422, "supported_languages": null}, "macro.dbt_duckdb.write_to_file": {"name": "write_to_file", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.write_to_file", "macro_sql": "{% macro write_to_file(relation, location, options) -%}\n  {% call statement('write_to_file') -%}\n    copy {{ relation }} to '{{ location }}' ({{ options }})\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.233629, "supported_languages": null}, "macro.dbt_duckdb.store_relation": {"name": "store_relation", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.store_relation", "macro_sql": "{% macro store_relation(plugin, relation, location, format, config) -%}\n  {%- set column_list = adapter.get_columns_in_relation(relation) -%}\n  {% do adapter.store_relation(plugin, relation, column_list, location, format, config) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.234048, "supported_languages": null}, "macro.dbt_duckdb.render_write_options": {"name": "render_write_options", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/adapters.sql", "original_file_path": "macros/adapters.sql", "unique_id": "macro.dbt_duckdb.render_write_options", "macro_sql": "{% macro render_write_options(config) -%}\n  {% set options = config.get('options', {}) %}\n  {% if options is not mapping %}\n    {% do exceptions.raise_compiler_error(\"The options argument must be a dictionary\") %}\n  {% endif %}\n\n  {% for k in options %}\n    {% set _ = options.update({k: render(options[k])}) %}\n  {% endfor %}\n\n  {# legacy top-level write options #}\n  {% if config.get('format') %}\n    {% set _ = options.update({'format': render(config.get('format'))}) %}\n  {% endif %}\n  {% if config.get('delimiter') %}\n    {% set _ = options.update({'delimiter': render(config.get('delimiter'))}) %}\n  {% endif %}\n\n  {% do return(options) %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.23509, "supported_languages": null}, "macro.dbt_duckdb.duckdb__get_delete_insert_merge_sql": {"name": "duckdb__get_delete_insert_merge_sql", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/incremental_helper.sql", "original_file_path": "macros/incremental_helper.sql", "unique_id": "macro.dbt_duckdb.duckdb__get_delete_insert_merge_sql", "macro_sql": "{% macro duckdb__get_delete_insert_merge_sql(target, source, unique_key, dest_columns, incremental_predicates) -%}\n\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n\n    {% if unique_key %}\n        {% if unique_key is sequence and unique_key is not string %}\n            delete from {{target }} as DBT_INCREMENTAL_TARGET\n            using {{ source }}\n            where (\n                {% for key in unique_key %}\n                    {{ source }}.{{ key }} = DBT_INCREMENTAL_TARGET.{{ key }}\n                    {{ \"and \" if not loop.last}}\n                {% endfor %}\n                {% if incremental_predicates %}\n                    {% for predicate in incremental_predicates %}\n                        and {{ predicate }}\n                    {% endfor %}\n                {% endif %}\n            );\n        {% else %}\n            delete from {{ target }}\n            where (\n                {{ unique_key }}) in (\n                select ({{ unique_key }})\n                from {{ source }}\n            )\n            {%- if incremental_predicates %}\n                {% for predicate in incremental_predicates %}\n                    and {{ predicate }}\n                {% endfor %}\n            {%- endif -%};\n\n        {% endif %}\n    {% endif %}\n\n    insert into {{ target }} ({{ dest_cols_csv }})\n    (\n        select {{ dest_cols_csv }}\n        from {{ source }}\n    )\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.237298, "supported_languages": null}, "macro.dbt_duckdb.duckdb__alter_relation_add_remove_columns": {"name": "duckdb__alter_relation_add_remove_columns", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/columns.sql", "original_file_path": "macros/columns.sql", "unique_id": "macro.dbt_duckdb.duckdb__alter_relation_add_remove_columns", "macro_sql": "{% macro duckdb__alter_relation_add_remove_columns(relation, add_columns, remove_columns) %}\n\n  {% if add_columns %}\n    {% for column in add_columns %}\n      {% set sql -%}\n         alter {{ relation.type }} {{ relation }} add column\n           {{ column.name }} {{ column.data_type }}\n      {%- endset -%}\n      {% do run_query(sql) %}\n    {% endfor %}\n  {% endif %}\n\n  {% if remove_columns %}\n    {% for column in remove_columns %}\n      {% set sql -%}\n        alter {{ relation.type }} {{ relation }} drop column\n          {{ column.name }}\n      {%- endset -%}\n      {% do run_query(sql) %}\n    {% endfor %}\n  {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.238336, "supported_languages": null}, "macro.dbt_duckdb.materialization_table_duckdb": {"name": "materialization_table_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/table.sql", "original_file_path": "macros/materializations/table.sql", "unique_id": "macro.dbt_duckdb.materialization_table_duckdb", "macro_sql": "{% materialization table, adapter=\"duckdb\", supported_languages=['sql', 'python'] %}\n\n  {%- set language = model['language'] -%}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') %}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main', language=language) -%}\n    {{- create_table_as(False, intermediate_relation, compiled_code, language) }}\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n      {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% do create_indexes(target_relation) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.create_table_as", "macro.dbt.create_indexes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.241374, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.materialization_external_duckdb": {"name": "materialization_external_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/external.sql", "original_file_path": "macros/materializations/external.sql", "unique_id": "macro.dbt_duckdb.materialization_external_duckdb", "macro_sql": "{% materialization external, adapter=\"duckdb\", supported_languages=['sql', 'python'] %}\n\n  {%- set location = render(config.get('location', default=external_location(this, config))) -%})\n  {%- set rendered_options = render_write_options(config) -%}\n  {%- set format = config.get('format', 'parquet') -%}\n  {%- set write_options = adapter.external_write_options(location, rendered_options) -%}\n  {%- set read_location = adapter.external_read_location(location, rendered_options) -%}\n\n  -- set language - python or sql\n  {%- set language = model['language'] -%}\n\n  {%- set target_relation = this.incorporate(type='view') %}\n\n  -- Continue as normal materialization\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set temp_relation =  make_intermediate_relation(this.incorporate(type='table'), suffix='__dbt_tmp') -%}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation, suffix='__dbt_int') -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_temp_relation = load_cached_relation(temp_relation) -%}\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_temp_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('create_table', language=language) -%}\n    {{- create_table_as(False, temp_relation, compiled_code, language) }}\n  {%- endcall %}\n\n  -- write an temp relation into file\n  {{ write_to_file(temp_relation, location, write_options) }}\n  -- create a view on top of the location\n  {% call statement('main', language='sql') -%}\n    create or replace view {{ intermediate_relation }} as (\n        select * from '{{ read_location }}'\n    );\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n      {{ adapter.rename_relation(existing_relation, backup_relation) }}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n  {{ drop_relation_if_exists(temp_relation) }}\n\n  -- register table into glue\n  {%- set plugin_name = config.get('plugin') -%}\n  {%- set glue_register = config.get('glue_register', default=false) -%}\n  {% if plugin_name is not none or glue_register is true %}\n    {% if glue_register %}\n      {# legacy hack to set the glue database name, deprecate this #}\n      {%- set plugin_name = 'glue|' ~ config.get('glue_database', 'default') -%}\n    {% endif %}\n    {% do store_relation(plugin_name, target_relation, location, format, config) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt_duckdb.external_location", "macro.dbt_duckdb.render_write_options", "macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.create_table_as", "macro.dbt_duckdb.write_to_file", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt_duckdb.store_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.246537, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.materialization_incremental_duckdb": {"name": "materialization_incremental_duckdb", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/materializations/incremental.sql", "original_file_path": "macros/materializations/incremental.sql", "unique_id": "macro.dbt_duckdb.materialization_incremental_duckdb", "macro_sql": "{% materialization incremental, adapter=\"duckdb\", supported_languages=['sql', 'python'] -%}\n\n  {%- set language = model['language'] -%}\n\n  -- relations\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') -%}\n  {%- set temp_relation = make_temp_relation(target_relation)-%}\n  {%- set intermediate_relation = make_intermediate_relation(target_relation)-%}\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n\n  -- configs\n  {%- set unique_key = config.get('unique_key') -%}\n  {%- set full_refresh_mode = (should_full_refresh()  or existing_relation.is_view) -%}\n  {%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%}\n\n  -- the temp_ and backup_ relations should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation. This has to happen before\n  -- BEGIN, in a separate transaction\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation)-%}\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n   -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set to_drop = [] %}\n\n  {% if existing_relation is none %}\n    {% set build_sql = create_table_as(False, target_relation, compiled_code, language) %}\n  {% elif full_refresh_mode %}\n    {% set build_sql = create_table_as(False, intermediate_relation, compiled_code, language) %}\n    {% set need_swap = true %}\n  {% else %}\n    {% if language == 'python' %}\n      {% set build_python = create_table_as(False, temp_relation, compiled_code, language) %}\n      {% call statement(\"pre\", language=language) %}\n        {{- build_python }}\n      {% endcall %}\n    {% else %} {# SQL #}\n      {% do run_query(create_table_as(True, temp_relation, compiled_code, language)) %}\n    {% endif %}\n    {% do adapter.expand_target_column_types(\n             from_relation=temp_relation,\n             to_relation=target_relation) %}\n    {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#}\n    {% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %}\n    {% if not dest_columns %}\n      {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %}\n    {% endif %}\n\n    {#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#}\n    {% set incremental_strategy = config.get('incremental_strategy') or 'default' %}\n    {% set incremental_predicates = config.get('predicates', none) or config.get('incremental_predicates', none) %}\n    {% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %}\n    {% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'incremental_predicates': incremental_predicates }) %}\n    {% set build_sql = strategy_sql_macro_func(strategy_arg_dict) %}\n    {% set language = \"sql\" %}\n\n  {% endif %}\n\n  {% call statement(\"main\", language=language) %}\n      {{- build_sql }}\n  {% endcall %}\n\n  {% if need_swap %}\n      {% do adapter.rename_relation(target_relation, backup_relation) %}\n      {% do adapter.rename_relation(intermediate_relation, target_relation) %}\n      {% do to_drop.append(backup_relation) %}\n  {% endif %}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if existing_relation is none or existing_relation.is_view or should_full_refresh() %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {% do adapter.commit() %}\n\n  {% for rel in to_drop %}\n      {% do adapter.drop_relation(rel) %}\n  {% endfor %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_temp_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.should_full_refresh", "macro.dbt.incremental_validate_on_schema_change", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.create_table_as", "macro.dbt.statement", "macro.dbt.run_query", "macro.dbt.process_schema_changes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.252039, "supported_languages": ["sql", "python"]}, "macro.dbt_duckdb.duckdb__dateadd": {"name": "duckdb__dateadd", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt_duckdb.duckdb__dateadd", "macro_sql": "{% macro duckdb__dateadd(datepart, interval, from_date_or_timestamp) %}\n\n    {{ from_date_or_timestamp }} + ((interval '1 {{ datepart }}') * ({{ interval }}))\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.252274, "supported_languages": null}, "macro.dbt_duckdb.duckdb__listagg": {"name": "duckdb__listagg", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt_duckdb.duckdb__listagg", "macro_sql": "{% macro duckdb__listagg(measure, delimiter_text, order_by_clause, limit_num) -%}\n    {% if limit_num -%}\n    list_aggr(\n        (array_agg(\n            {{ measure }}\n            {% if order_by_clause -%}\n            {{ order_by_clause }}\n            {%- endif %}\n        ))[1:{{ limit_num }}],\n        'string_agg',\n        {{ delimiter_text }}\n        )\n    {%- else %}\n    string_agg(\n        {{ measure }},\n        {{ delimiter_text }}\n        {% if order_by_clause -%}\n        {{ order_by_clause }}\n        {%- endif %}\n        )\n    {%- endif %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2529438, "supported_languages": null}, "macro.dbt_duckdb.duckdb__datediff": {"name": "duckdb__datediff", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt_duckdb.duckdb__datediff", "macro_sql": "{% macro duckdb__datediff(first_date, second_date, datepart) -%}\n\n    {% if datepart == 'year' %}\n        (date_part('year', ({{second_date}})::date) - date_part('year', ({{first_date}})::date))\n    {% elif datepart == 'quarter' %}\n        ({{ datediff(first_date, second_date, 'year') }} * 4 + date_part('quarter', ({{second_date}})::date) - date_part('quarter', ({{first_date}})::date))\n    {% elif datepart == 'month' %}\n        ({{ datediff(first_date, second_date, 'year') }} * 12 + date_part('month', ({{second_date}})::date) - date_part('month', ({{first_date}})::date))\n    {% elif datepart == 'day' %}\n        (({{second_date}})::date - ({{first_date}})::date)\n    {% elif datepart == 'week' %}\n        ({{ datediff(first_date, second_date, 'day') }} / 7 + case\n            when date_part('dow', ({{first_date}})::timestamp) <= date_part('dow', ({{second_date}})::timestamp) then\n                case when {{first_date}} <= {{second_date}} then 0 else -1 end\n            else\n                case when {{first_date}} <= {{second_date}} then 1 else 0 end\n        end)\n    {% elif datepart == 'hour' %}\n        ({{ datediff(first_date, second_date, 'day') }} * 24 + date_part('hour', ({{second_date}})::timestamp) - date_part('hour', ({{first_date}})::timestamp))\n    {% elif datepart == 'minute' %}\n        ({{ datediff(first_date, second_date, 'hour') }} * 60 + date_part('minute', ({{second_date}})::timestamp) - date_part('minute', ({{first_date}})::timestamp))\n    {% elif datepart == 'second' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60 + floor(date_part('second', ({{second_date}})::timestamp)) - floor(date_part('second', ({{first_date}})::timestamp)))\n    {% elif datepart == 'millisecond' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60000 + floor(date_part('millisecond', ({{second_date}})::timestamp)) - floor(date_part('millisecond', ({{first_date}})::timestamp)))\n    {% elif datepart == 'microsecond' %}\n        ({{ datediff(first_date, second_date, 'minute') }} * 60000000 + floor(date_part('microsecond', ({{second_date}})::timestamp)) - floor(date_part('microsecond', ({{first_date}})::timestamp)))\n    {% else %}\n        {{ exceptions.raise_compiler_error(\"Unsupported datepart for macro datediff in postgres: {!r}\".format(datepart)) }}\n    {% endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.datediff"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.256305, "supported_languages": null}, "macro.dbt_duckdb.duckdb__any_value": {"name": "duckdb__any_value", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt_duckdb.duckdb__any_value", "macro_sql": "{% macro duckdb__any_value(expression) -%}\n\n    arbitrary({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.256445, "supported_languages": null}, "macro.dbt_duckdb.register_upstream_external_models": {"name": "register_upstream_external_models", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/upstream.sql", "original_file_path": "macros/utils/upstream.sql", "unique_id": "macro.dbt_duckdb.register_upstream_external_models", "macro_sql": "{%- macro register_upstream_external_models() -%}\n{% if execute %}\n{% set upstream_nodes = {} %}\n{% set upstream_schemas = {} %}\n{% for node in selected_resources %}\n  {% for upstream_node in graph['nodes'][node]['depends_on']['nodes'] %}\n    {% if upstream_node not in upstream_nodes and upstream_node not in selected_resources %}\n      {% do upstream_nodes.update({upstream_node: None}) %}\n      {% set upstream = graph['nodes'].get(upstream_node) %}\n      {% if upstream\n         and upstream.resource_type in ('model', 'seed')\n         and upstream.config.materialized=='external'\n      %}\n        {%- set upstream_rel = api.Relation.create(\n          database=upstream['database'],\n          schema=upstream['schema'],\n          identifier=upstream['alias']\n        ) -%}\n        {%- set location = upstream.config.get('location', external_location(upstream_rel, upstream.config)) -%}\n        {%- set rendered_options = render_write_options(upstream.config) -%}\n        {%- set upstream_location = adapter.external_read_location(location, rendered_options) -%}\n        {% if upstream_rel.schema not in upstream_schemas %}\n          {% call statement('main', language='sql') -%}\n            create schema if not exists {{ upstream_rel.schema }}\n          {%- endcall %}\n          {% do upstream_schemas.update({upstream_rel.schema: None}) %}\n        {% endif %}\n        {% call statement('main', language='sql') -%}\n          create or replace view {{ upstream_rel }} as (\n            select * from '{{ upstream_location }}'\n          );\n        {%- endcall %}\n      {%- endif %}\n    {% endif %}\n  {% endfor %}\n{% endfor %}\n{% do adapter.commit() %}\n{% endif %}\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt_duckdb.external_location", "macro.dbt_duckdb.render_write_options", "macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2589571, "supported_languages": null}, "macro.dbt_duckdb.duckdb__split_part": {"name": "duckdb__split_part", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/splitpart.sql", "original_file_path": "macros/utils/splitpart.sql", "unique_id": "macro.dbt_duckdb.duckdb__split_part", "macro_sql": "{% macro duckdb__split_part(string_text, delimiter_text, part_number) %}\n    string_split({{ string_text }}, {{ delimiter_text }})[ {{ part_number }} ]\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2591739, "supported_languages": null}, "macro.dbt_duckdb.duckdb__last_day": {"name": "duckdb__last_day", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/lastday.sql", "original_file_path": "macros/utils/lastday.sql", "unique_id": "macro.dbt_duckdb.duckdb__last_day", "macro_sql": "{% macro duckdb__last_day(date, datepart) -%}\n\n    {%- if datepart == 'quarter' -%}\n    -- duckdb dateadd does not support quarter interval.\n    cast(\n        {{dbt.dateadd('day', '-1',\n        dbt.dateadd('month', '3', dbt.date_trunc(datepart, date))\n        )}}\n        as date)\n    {%- else -%}\n    {{dbt.default_last_day(date, datepart)}}\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.dateadd", "macro.dbt.date_trunc", "macro.dbt.default_last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2596638, "supported_languages": null}, "macro.dbt_duckdb.external_location": {"name": "external_location", "resource_type": "macro", "package_name": "dbt_duckdb", "path": "macros/utils/external_location.sql", "original_file_path": "macros/utils/external_location.sql", "unique_id": "macro.dbt_duckdb.external_location", "macro_sql": "{%- macro external_location(relation, config) -%}\n  {%- if config.get('options', {}).get('partition_by') is none -%}\n    {%- set format = config.get('format', 'parquet') -%}\n    {{- adapter.external_root() }}/{{ relation.identifier }}.{{ format }}\n  {%- else -%}\n    {{- adapter.external_root() }}/{{ relation.identifier }}\n  {%- endif -%}\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.260224, "supported_languages": null}, "macro.dbt.run_hooks": {"name": "run_hooks", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.run_hooks", "macro_sql": "{% macro run_hooks(hooks, inside_transaction=True) %}\n  {% for hook in hooks | selectattr('transaction', 'equalto', inside_transaction)  %}\n    {% if not inside_transaction and loop.first %}\n      {% call statement(auto_begin=inside_transaction) %}\n        commit;\n      {% endcall %}\n    {% endif %}\n    {% set rendered = render(hook.get('sql')) | trim %}\n    {% if (rendered | length) > 0 %}\n      {% call statement(auto_begin=inside_transaction) %}\n        {{ rendered }}\n      {% endcall %}\n    {% endif %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.261298, "supported_languages": null}, "macro.dbt.make_hook_config": {"name": "make_hook_config", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.make_hook_config", "macro_sql": "{% macro make_hook_config(sql, inside_transaction) %}\n    {{ tojson({\"sql\": sql, \"transaction\": inside_transaction}) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.261497, "supported_languages": null}, "macro.dbt.before_begin": {"name": "before_begin", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.before_begin", "macro_sql": "{% macro before_begin(sql) %}\n    {{ make_hook_config(sql, inside_transaction=False) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.261643, "supported_languages": null}, "macro.dbt.in_transaction": {"name": "in_transaction", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.in_transaction", "macro_sql": "{% macro in_transaction(sql) %}\n    {{ make_hook_config(sql, inside_transaction=True) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.261805, "supported_languages": null}, "macro.dbt.after_commit": {"name": "after_commit", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/hooks.sql", "original_file_path": "macros/materializations/hooks.sql", "unique_id": "macro.dbt.after_commit", "macro_sql": "{% macro after_commit(sql) %}\n    {{ make_hook_config(sql, inside_transaction=False) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_hook_config"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.261951, "supported_languages": null}, "macro.dbt.set_sql_header": {"name": "set_sql_header", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.set_sql_header", "macro_sql": "{% macro set_sql_header(config) -%}\n  {{ config.set('sql_header', caller()) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.262305, "supported_languages": null}, "macro.dbt.should_full_refresh": {"name": "should_full_refresh", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.should_full_refresh", "macro_sql": "{% macro should_full_refresh() %}\n  {% set config_full_refresh = config.get('full_refresh') %}\n  {% if config_full_refresh is none %}\n    {% set config_full_refresh = flags.FULL_REFRESH %}\n  {% endif %}\n  {% do return(config_full_refresh) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2626119, "supported_languages": null}, "macro.dbt.should_store_failures": {"name": "should_store_failures", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/configs.sql", "original_file_path": "macros/materializations/configs.sql", "unique_id": "macro.dbt.should_store_failures", "macro_sql": "{% macro should_store_failures() %}\n  {% set config_store_failures = config.get('store_failures') %}\n  {% if config_store_failures is none %}\n    {% set config_store_failures = flags.STORE_FAILURES %}\n  {% endif %}\n  {% do return(config_store_failures) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.262914, "supported_languages": null}, "macro.dbt.snapshot_merge_sql": {"name": "snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot_merge.sql", "original_file_path": "macros/materializations/snapshots/snapshot_merge.sql", "unique_id": "macro.dbt.snapshot_merge_sql", "macro_sql": "{% macro snapshot_merge_sql(target, source, insert_cols) -%}\n  {{ adapter.dispatch('snapshot_merge_sql', 'dbt')(target, source, insert_cols) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.263359, "supported_languages": null}, "macro.dbt.default__snapshot_merge_sql": {"name": "default__snapshot_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot_merge.sql", "original_file_path": "macros/materializations/snapshots/snapshot_merge.sql", "unique_id": "macro.dbt.default__snapshot_merge_sql", "macro_sql": "{% macro default__snapshot_merge_sql(target, source, insert_cols) -%}\n    {%- set insert_cols_csv = insert_cols | join(', ') -%}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n    using {{ source }} as DBT_INTERNAL_SOURCE\n    on DBT_INTERNAL_SOURCE.dbt_scd_id = DBT_INTERNAL_DEST.dbt_scd_id\n\n    when matched\n     and DBT_INTERNAL_DEST.dbt_valid_to is null\n     and DBT_INTERNAL_SOURCE.dbt_change_type in ('update', 'delete')\n        then update\n        set dbt_valid_to = DBT_INTERNAL_SOURCE.dbt_valid_to\n\n    when not matched\n     and DBT_INTERNAL_SOURCE.dbt_change_type = 'insert'\n        then insert ({{ insert_cols_csv }})\n        values ({{ insert_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.263625, "supported_languages": null}, "macro.dbt.strategy_dispatch": {"name": "strategy_dispatch", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.strategy_dispatch", "macro_sql": "{% macro strategy_dispatch(name) -%}\n{% set original_name = name %}\n  {% if '.' in name %}\n    {% set package_name, name = name.split(\".\", 1) %}\n  {% else %}\n    {% set package_name = none %}\n  {% endif %}\n\n  {% if package_name is none %}\n    {% set package_context = context %}\n  {% elif package_name in context %}\n    {% set package_context = context[package_name] %}\n  {% else %}\n    {% set error_msg %}\n        Could not find package '{{package_name}}', called with '{{original_name}}'\n    {% endset %}\n    {{ exceptions.raise_compiler_error(error_msg | trim) }}\n  {% endif %}\n\n  {%- set search_name = 'snapshot_' ~ name ~ '_strategy' -%}\n\n  {% if search_name not in package_context %}\n    {% set error_msg %}\n        The specified strategy macro '{{name}}' was not found in package '{{ package_name }}'\n    {% endset %}\n    {{ exceptions.raise_compiler_error(error_msg | trim) }}\n  {% endif %}\n  {{ return(package_context[search_name]) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.267334, "supported_languages": null}, "macro.dbt.snapshot_hash_arguments": {"name": "snapshot_hash_arguments", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_hash_arguments", "macro_sql": "{% macro snapshot_hash_arguments(args) -%}\n  {{ adapter.dispatch('snapshot_hash_arguments', 'dbt')(args) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.267494, "supported_languages": null}, "macro.dbt.default__snapshot_hash_arguments": {"name": "default__snapshot_hash_arguments", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.default__snapshot_hash_arguments", "macro_sql": "{% macro default__snapshot_hash_arguments(args) -%}\n    md5({%- for arg in args -%}\n        coalesce(cast({{ arg }} as varchar ), '')\n        {% if not loop.last %} || '|' || {% endif %}\n    {%- endfor -%})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2677, "supported_languages": null}, "macro.dbt.snapshot_timestamp_strategy": {"name": "snapshot_timestamp_strategy", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_timestamp_strategy", "macro_sql": "{% macro snapshot_timestamp_strategy(node, snapshotted_rel, current_rel, config, target_exists) %}\n    {% set primary_key = config['unique_key'] %}\n    {% set updated_at = config['updated_at'] %}\n    {% set invalidate_hard_deletes = config.get('invalidate_hard_deletes', false) %}\n\n    {#/*\n        The snapshot relation might not have an {{ updated_at }} value if the\n        snapshot strategy is changed from `check` to `timestamp`. We\n        should use a dbt-created column for the comparison in the snapshot\n        table instead of assuming that the user-supplied {{ updated_at }}\n        will be present in the historical data.\n\n        See https://github.com/dbt-labs/dbt-core/issues/2350\n    */ #}\n    {% set row_changed_expr -%}\n        ({{ snapshotted_rel }}.dbt_valid_from < {{ current_rel }}.{{ updated_at }})\n    {%- endset %}\n\n    {% set scd_id_expr = snapshot_hash_arguments([primary_key, updated_at]) %}\n\n    {% do return({\n        \"unique_key\": primary_key,\n        \"updated_at\": updated_at,\n        \"row_changed\": row_changed_expr,\n        \"scd_id\": scd_id_expr,\n        \"invalidate_hard_deletes\": invalidate_hard_deletes\n    }) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.268401, "supported_languages": null}, "macro.dbt.snapshot_string_as_time": {"name": "snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_string_as_time", "macro_sql": "{% macro snapshot_string_as_time(timestamp) -%}\n    {{ adapter.dispatch('snapshot_string_as_time', 'dbt')(timestamp) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_string_as_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.268558, "supported_languages": null}, "macro.dbt.default__snapshot_string_as_time": {"name": "default__snapshot_string_as_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.default__snapshot_string_as_time", "macro_sql": "{% macro default__snapshot_string_as_time(timestamp) %}\n    {% do exceptions.raise_not_implemented(\n        'snapshot_string_as_time macro not implemented for adapter '+adapter.type()\n    ) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.268734, "supported_languages": null}, "macro.dbt.snapshot_check_all_get_existing_columns": {"name": "snapshot_check_all_get_existing_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_check_all_get_existing_columns", "macro_sql": "{% macro snapshot_check_all_get_existing_columns(node, target_exists, check_cols_config) -%}\n    {%- if not target_exists -%}\n        {#-- no table yet -> return whatever the query does --#}\n        {{ return((false, query_columns)) }}\n    {%- endif -%}\n\n    {#-- handle any schema changes --#}\n    {%- set target_relation = adapter.get_relation(database=node.database, schema=node.schema, identifier=node.alias) -%}\n\n    {% if check_cols_config == 'all' %}\n        {%- set query_columns = get_columns_in_query(node['compiled_code']) -%}\n\n    {% elif check_cols_config is iterable and (check_cols_config | length) > 0 %}\n        {#-- query for proper casing/quoting, to support comparison below --#}\n        {%- set select_check_cols_from_target -%}\n            {#-- N.B. The whitespace below is necessary to avoid edge case issue with comments --#}\n            {#-- See: https://github.com/dbt-labs/dbt-core/issues/6781 --#}\n            select {{ check_cols_config | join(', ') }} from (\n                {{ node['compiled_code'] }}\n            ) subq\n        {%- endset -%}\n        {% set query_columns = get_columns_in_query(select_check_cols_from_target) %}\n\n    {% else %}\n        {% do exceptions.raise_compiler_error(\"Invalid value for 'check_cols': \" ~ check_cols_config) %}\n    {% endif %}\n\n    {%- set existing_cols = adapter.get_columns_in_relation(target_relation) | map(attribute = 'name') | list -%}\n    {%- set ns = namespace() -%} {#-- handle for-loop scoping with a namespace --#}\n    {%- set ns.column_added = false -%}\n\n    {%- set intersection = [] -%}\n    {%- for col in query_columns -%}\n        {%- if col in existing_cols -%}\n            {%- do intersection.append(adapter.quote(col)) -%}\n        {%- else -%}\n            {% set ns.column_added = true %}\n        {%- endif -%}\n    {%- endfor -%}\n    {{ return((ns.column_added, intersection)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_columns_in_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2701252, "supported_languages": null}, "macro.dbt.snapshot_check_strategy": {"name": "snapshot_check_strategy", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/strategies.sql", "original_file_path": "macros/materializations/snapshots/strategies.sql", "unique_id": "macro.dbt.snapshot_check_strategy", "macro_sql": "{% macro snapshot_check_strategy(node, snapshotted_rel, current_rel, config, target_exists) %}\n    {% set check_cols_config = config['check_cols'] %}\n    {% set primary_key = config['unique_key'] %}\n    {% set invalidate_hard_deletes = config.get('invalidate_hard_deletes', false) %}\n    {% set updated_at = config.get('updated_at', snapshot_get_time()) %}\n\n    {% set column_added = false %}\n\n    {% set column_added, check_cols = snapshot_check_all_get_existing_columns(node, target_exists, check_cols_config) %}\n\n    {%- set row_changed_expr -%}\n    (\n    {%- if column_added -%}\n        {{ get_true_sql() }}\n    {%- else -%}\n    {%- for col in check_cols -%}\n        {{ snapshotted_rel }}.{{ col }} != {{ current_rel }}.{{ col }}\n        or\n        (\n            (({{ snapshotted_rel }}.{{ col }} is null) and not ({{ current_rel }}.{{ col }} is null))\n            or\n            ((not {{ snapshotted_rel }}.{{ col }} is null) and ({{ current_rel }}.{{ col }} is null))\n        )\n        {%- if not loop.last %} or {% endif -%}\n    {%- endfor -%}\n    {%- endif -%}\n    )\n    {%- endset %}\n\n    {% set scd_id_expr = snapshot_hash_arguments([primary_key, updated_at]) %}\n\n    {% do return({\n        \"unique_key\": primary_key,\n        \"updated_at\": updated_at,\n        \"row_changed\": row_changed_expr,\n        \"scd_id\": scd_id_expr,\n        \"invalidate_hard_deletes\": invalidate_hard_deletes\n    }) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_get_time", "macro.dbt.snapshot_check_all_get_existing_columns", "macro.dbt.get_true_sql", "macro.dbt.snapshot_hash_arguments"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.271523, "supported_languages": null}, "macro.dbt.create_columns": {"name": "create_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.create_columns", "macro_sql": "{% macro create_columns(relation, columns) %}\n  {{ adapter.dispatch('create_columns', 'dbt')(relation, columns) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.275705, "supported_languages": null}, "macro.dbt.default__create_columns": {"name": "default__create_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__create_columns", "macro_sql": "{% macro default__create_columns(relation, columns) %}\n  {% for column in columns %}\n    {% call statement() %}\n      alter table {{ relation }} add column \"{{ column.name }}\" {{ column.data_type }};\n    {% endcall %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.275985, "supported_languages": null}, "macro.dbt.post_snapshot": {"name": "post_snapshot", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.post_snapshot", "macro_sql": "{% macro post_snapshot(staging_relation) %}\n  {{ adapter.dispatch('post_snapshot', 'dbt')(staging_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__post_snapshot"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.276147, "supported_languages": null}, "macro.dbt.default__post_snapshot": {"name": "default__post_snapshot", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__post_snapshot", "macro_sql": "{% macro default__post_snapshot(staging_relation) %}\n    {# no-op #}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.276243, "supported_languages": null}, "macro.dbt.get_true_sql": {"name": "get_true_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.get_true_sql", "macro_sql": "{% macro get_true_sql() %}\n  {{ adapter.dispatch('get_true_sql', 'dbt')() }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_true_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.276404, "supported_languages": null}, "macro.dbt.default__get_true_sql": {"name": "default__get_true_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__get_true_sql", "macro_sql": "{% macro default__get_true_sql() %}\n    {{ return('TRUE') }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.27652, "supported_languages": null}, "macro.dbt.snapshot_staging_table": {"name": "snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.snapshot_staging_table", "macro_sql": "{% macro snapshot_staging_table(strategy, source_sql, target_relation) -%}\n  {{ adapter.dispatch('snapshot_staging_table', 'dbt')(strategy, source_sql, target_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__snapshot_staging_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2767382, "supported_languages": null}, "macro.dbt.default__snapshot_staging_table": {"name": "default__snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__snapshot_staging_table", "macro_sql": "{% macro default__snapshot_staging_table(strategy, source_sql, target_relation) -%}\n\n    with snapshot_query as (\n\n        {{ source_sql }}\n\n    ),\n\n    snapshotted_data as (\n\n        select *,\n            {{ strategy.unique_key }} as dbt_unique_key\n\n        from {{ target_relation }}\n        where dbt_valid_to is null\n\n    ),\n\n    insertions_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key,\n            {{ strategy.updated_at }} as dbt_updated_at,\n            {{ strategy.updated_at }} as dbt_valid_from,\n            nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) as dbt_valid_to,\n            {{ strategy.scd_id }} as dbt_scd_id\n\n        from snapshot_query\n    ),\n\n    updates_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key,\n            {{ strategy.updated_at }} as dbt_updated_at,\n            {{ strategy.updated_at }} as dbt_valid_from,\n            {{ strategy.updated_at }} as dbt_valid_to\n\n        from snapshot_query\n    ),\n\n    {%- if strategy.invalidate_hard_deletes %}\n\n    deletes_source_data as (\n\n        select\n            *,\n            {{ strategy.unique_key }} as dbt_unique_key\n        from snapshot_query\n    ),\n    {% endif %}\n\n    insertions as (\n\n        select\n            'insert' as dbt_change_type,\n            source_data.*\n\n        from insertions_source_data as source_data\n        left outer join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where snapshotted_data.dbt_unique_key is null\n           or (\n                snapshotted_data.dbt_unique_key is not null\n            and (\n                {{ strategy.row_changed }}\n            )\n        )\n\n    ),\n\n    updates as (\n\n        select\n            'update' as dbt_change_type,\n            source_data.*,\n            snapshotted_data.dbt_scd_id\n\n        from updates_source_data as source_data\n        join snapshotted_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where (\n            {{ strategy.row_changed }}\n        )\n    )\n\n    {%- if strategy.invalidate_hard_deletes -%}\n    ,\n\n    deletes as (\n\n        select\n            'delete' as dbt_change_type,\n            source_data.*,\n            {{ snapshot_get_time() }} as dbt_valid_from,\n            {{ snapshot_get_time() }} as dbt_updated_at,\n            {{ snapshot_get_time() }} as dbt_valid_to,\n            snapshotted_data.dbt_scd_id\n\n        from snapshotted_data\n        left join deletes_source_data as source_data on snapshotted_data.dbt_unique_key = source_data.dbt_unique_key\n        where source_data.dbt_unique_key is null\n    )\n    {%- endif %}\n\n    select * from insertions\n    union all\n    select * from updates\n    {%- if strategy.invalidate_hard_deletes %}\n    union all\n    select * from deletes\n    {%- endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.snapshot_get_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2776792, "supported_languages": null}, "macro.dbt.build_snapshot_table": {"name": "build_snapshot_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.build_snapshot_table", "macro_sql": "{% macro build_snapshot_table(strategy, sql) -%}\n  {{ adapter.dispatch('build_snapshot_table', 'dbt')(strategy, sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__build_snapshot_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.277874, "supported_languages": null}, "macro.dbt.default__build_snapshot_table": {"name": "default__build_snapshot_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.default__build_snapshot_table", "macro_sql": "{% macro default__build_snapshot_table(strategy, sql) %}\n\n    select *,\n        {{ strategy.scd_id }} as dbt_scd_id,\n        {{ strategy.updated_at }} as dbt_updated_at,\n        {{ strategy.updated_at }} as dbt_valid_from,\n        nullif({{ strategy.updated_at }}, {{ strategy.updated_at }}) as dbt_valid_to\n    from (\n        {{ sql }}\n    ) sbq\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.278126, "supported_languages": null}, "macro.dbt.build_snapshot_staging_table": {"name": "build_snapshot_staging_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/helpers.sql", "original_file_path": "macros/materializations/snapshots/helpers.sql", "unique_id": "macro.dbt.build_snapshot_staging_table", "macro_sql": "{% macro build_snapshot_staging_table(strategy, sql, target_relation) %}\n    {% set temp_relation = make_temp_relation(target_relation) %}\n\n    {% set select = snapshot_staging_table(strategy, sql, target_relation) %}\n\n    {% call statement('build_snapshot_staging_relation') %}\n        {{ create_table_as(True, temp_relation, select) }}\n    {% endcall %}\n\n    {% do return(temp_relation) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.make_temp_relation", "macro.dbt.snapshot_staging_table", "macro.dbt.statement", "macro.dbt.create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.278594, "supported_languages": null}, "macro.dbt.materialization_snapshot_default": {"name": "materialization_snapshot_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/snapshots/snapshot.sql", "original_file_path": "macros/materializations/snapshots/snapshot.sql", "unique_id": "macro.dbt.materialization_snapshot_default", "macro_sql": "{% materialization snapshot, default %}\n  {%- set config = model['config'] -%}\n\n  {%- set target_table = model.get('alias', model.get('name')) -%}\n\n  {%- set strategy_name = config.get('strategy') -%}\n  {%- set unique_key = config.get('unique_key') %}\n  -- grab current tables grants config for comparision later on\n  {%- set grant_config = config.get('grants') -%}\n\n  {% set target_relation_exists, target_relation = get_or_create_relation(\n          database=model.database,\n          schema=model.schema,\n          identifier=target_table,\n          type='table') -%}\n\n  {%- if not target_relation.is_table -%}\n    {% do exceptions.relation_wrong_type(target_relation, 'table') %}\n  {%- endif -%}\n\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set strategy_macro = strategy_dispatch(strategy_name) %}\n  {% set strategy = strategy_macro(model, \"snapshotted_data\", \"source_data\", config, target_relation_exists) %}\n\n  {% if not target_relation_exists %}\n\n      {% set build_sql = build_snapshot_table(strategy, model['compiled_code']) %}\n      {% set final_sql = create_table_as(False, target_relation, build_sql) %}\n\n  {% else %}\n\n      {{ adapter.valid_snapshot_target(target_relation) }}\n\n      {% set staging_table = build_snapshot_staging_table(strategy, sql, target_relation) %}\n\n      -- this may no-op if the database does not require column expansion\n      {% do adapter.expand_target_column_types(from_relation=staging_table,\n                                               to_relation=target_relation) %}\n\n      {% set missing_columns = adapter.get_missing_columns(staging_table, target_relation)\n                                   | rejectattr('name', 'equalto', 'dbt_change_type')\n                                   | rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')\n                                   | rejectattr('name', 'equalto', 'dbt_unique_key')\n                                   | rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')\n                                   | list %}\n\n      {% do create_columns(target_relation, missing_columns) %}\n\n      {% set source_columns = adapter.get_columns_in_relation(staging_table)\n                                   | rejectattr('name', 'equalto', 'dbt_change_type')\n                                   | rejectattr('name', 'equalto', 'DBT_CHANGE_TYPE')\n                                   | rejectattr('name', 'equalto', 'dbt_unique_key')\n                                   | rejectattr('name', 'equalto', 'DBT_UNIQUE_KEY')\n                                   | list %}\n\n      {% set quoted_source_columns = [] %}\n      {% for column in source_columns %}\n        {% do quoted_source_columns.append(adapter.quote(column.name)) %}\n      {% endfor %}\n\n      {% set final_sql = snapshot_merge_sql(\n            target = target_relation,\n            source = staging_table,\n            insert_cols = quoted_source_columns\n         )\n      %}\n\n  {% endif %}\n\n  {% call statement('main') %}\n      {{ final_sql }}\n  {% endcall %}\n\n  {% set should_revoke = should_revoke(target_relation_exists, full_refresh_mode=False) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if not target_relation_exists %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {{ adapter.commit() }}\n\n  {% if staging_table is defined %}\n      {% do post_snapshot(staging_table) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.get_or_create_relation", "macro.dbt.run_hooks", "macro.dbt.strategy_dispatch", "macro.dbt.build_snapshot_table", "macro.dbt.create_table_as", "macro.dbt.build_snapshot_staging_table", "macro.dbt.create_columns", "macro.dbt.snapshot_merge_sql", "macro.dbt.statement", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes", "macro.dbt.post_snapshot"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.285076, "supported_languages": ["sql"]}, "macro.dbt.materialization_test_default": {"name": "materialization_test_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/test.sql", "original_file_path": "macros/materializations/tests/test.sql", "unique_id": "macro.dbt.materialization_test_default", "macro_sql": "{%- materialization test, default -%}\n\n  {% set relations = [] %}\n\n  {% if should_store_failures() %}\n\n    {% set identifier = model['alias'] %}\n    {% set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) %}\n\n    {% set store_failures_as = config.get('store_failures_as') %}\n    -- if `--store-failures` is invoked via command line and `store_failures_as` is not set,\n    -- config.get('store_failures_as', 'table') returns None, not 'table'\n    {% if store_failures_as == none %}{% set store_failures_as = 'table' %}{% endif %}\n    {% if store_failures_as not in ['table', 'view'] %}\n        {{ exceptions.raise_compiler_error(\n            \"'\" ~ store_failures_as ~ \"' is not a valid value for `store_failures_as`. \"\n            \"Accepted values are: ['ephemeral', 'table', 'view']\"\n        ) }}\n    {% endif %}\n\n    {% set target_relation = api.Relation.create(\n        identifier=identifier, schema=schema, database=database, type=store_failures_as) -%} %}\n\n    {% if old_relation %}\n        {% do adapter.drop_relation(old_relation) %}\n    {% endif %}\n\n    {% call statement(auto_begin=True) %}\n        {{ get_create_sql(target_relation, sql) }}\n    {% endcall %}\n\n    {% do relations.append(target_relation) %}\n\n    {% set main_sql %}\n        select *\n        from {{ target_relation }}\n    {% endset %}\n\n    {{ adapter.commit() }}\n\n  {% else %}\n\n      {% set main_sql = sql %}\n\n  {% endif %}\n\n  {% set limit = config.get('limit') %}\n  {% set fail_calc = config.get('fail_calc') %}\n  {% set warn_if = config.get('warn_if') %}\n  {% set error_if = config.get('error_if') %}\n\n  {% call statement('main', fetch_result=True) -%}\n\n    {{ get_test_sql(main_sql, fail_calc, warn_if, error_if, limit)}}\n\n  {%- endcall %}\n\n  {{ return({'relations': relations}) }}\n\n{%- endmaterialization -%}", "depends_on": {"macros": ["macro.dbt.should_store_failures", "macro.dbt.statement", "macro.dbt.get_create_sql", "macro.dbt.get_test_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.287831, "supported_languages": ["sql"]}, "macro.dbt.get_test_sql": {"name": "get_test_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/helpers.sql", "original_file_path": "macros/materializations/tests/helpers.sql", "unique_id": "macro.dbt.get_test_sql", "macro_sql": "{% macro get_test_sql(main_sql, fail_calc, warn_if, error_if, limit) -%}\n  {{ adapter.dispatch('get_test_sql', 'dbt')(main_sql, fail_calc, warn_if, error_if, limit) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_test_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.288308, "supported_languages": null}, "macro.dbt.default__get_test_sql": {"name": "default__get_test_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/helpers.sql", "original_file_path": "macros/materializations/tests/helpers.sql", "unique_id": "macro.dbt.default__get_test_sql", "macro_sql": "{% macro default__get_test_sql(main_sql, fail_calc, warn_if, error_if, limit) -%}\n    select\n      {{ fail_calc }} as failures,\n      {{ fail_calc }} {{ warn_if }} as should_warn,\n      {{ fail_calc }} {{ error_if }} as should_error\n    from (\n      {{ main_sql }}\n      {{ \"limit \" ~ limit if limit != none }}\n    ) dbt_internal_test\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.28864, "supported_languages": null}, "macro.dbt.get_where_subquery": {"name": "get_where_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/where_subquery.sql", "original_file_path": "macros/materializations/tests/where_subquery.sql", "unique_id": "macro.dbt.get_where_subquery", "macro_sql": "{% macro get_where_subquery(relation) -%}\n    {% do return(adapter.dispatch('get_where_subquery', 'dbt')(relation)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_where_subquery"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.289033, "supported_languages": null}, "macro.dbt.default__get_where_subquery": {"name": "default__get_where_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/tests/where_subquery.sql", "original_file_path": "macros/materializations/tests/where_subquery.sql", "unique_id": "macro.dbt.default__get_where_subquery", "macro_sql": "{% macro default__get_where_subquery(relation) -%}\n    {% set where = config.get('where', '') %}\n    {% if where %}\n        {%- set filtered -%}\n            (select * from {{ relation }} where {{ where }}) dbt_subquery\n        {%- endset -%}\n        {% do return(filtered) %}\n    {%- else -%}\n        {% do return(relation) %}\n    {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2894359, "supported_languages": null}, "macro.dbt.materialization_materialized_view_default": {"name": "materialization_materialized_view_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialization_materialized_view_default", "macro_sql": "{% materialization materialized_view, default %}\n    {% set existing_relation = load_cached_relation(this) %}\n    {% set target_relation = this.incorporate(type=this.MaterializedView) %}\n    {% set intermediate_relation = make_intermediate_relation(target_relation) %}\n    {% set backup_relation_type = target_relation.MaterializedView if existing_relation is none else existing_relation.type %}\n    {% set backup_relation = make_backup_relation(target_relation, backup_relation_type) %}\n\n    {{ materialized_view_setup(backup_relation, intermediate_relation, pre_hooks) }}\n\n        {% set build_sql = materialized_view_get_build_sql(existing_relation, target_relation, backup_relation, intermediate_relation) %}\n\n        {% if build_sql == '' %}\n            {{ materialized_view_execute_no_op(target_relation) }}\n        {% else %}\n            {{ materialized_view_execute_build_sql(build_sql, existing_relation, target_relation, post_hooks) }}\n        {% endif %}\n\n    {{ materialized_view_teardown(backup_relation, intermediate_relation, post_hooks) }}\n\n    {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.materialized_view_setup", "macro.dbt.materialized_view_get_build_sql", "macro.dbt.materialized_view_execute_no_op", "macro.dbt.materialized_view_execute_build_sql", "macro.dbt.materialized_view_teardown"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.294364, "supported_languages": ["sql"]}, "macro.dbt.materialized_view_setup": {"name": "materialized_view_setup", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialized_view_setup", "macro_sql": "{% macro materialized_view_setup(backup_relation, intermediate_relation, pre_hooks) %}\n\n    -- backup_relation and intermediate_relation should not already exist in the database\n    -- it's possible these exist because of a previous run that exited unexpectedly\n    {% set preexisting_backup_relation = load_cached_relation(backup_relation) %}\n    {% set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) %}\n\n    -- drop the temp relations if they exist already in the database\n    {{ drop_relation_if_exists(preexisting_backup_relation) }}\n    {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n\n    {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.2947588, "supported_languages": null}, "macro.dbt.materialized_view_teardown": {"name": "materialized_view_teardown", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialized_view_teardown", "macro_sql": "{% macro materialized_view_teardown(backup_relation, intermediate_relation, post_hooks) %}\n\n    -- drop the temp relations if they exist to leave the database clean for the next run\n    {{ drop_relation_if_exists(backup_relation) }}\n    {{ drop_relation_if_exists(intermediate_relation) }}\n\n    {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.295027, "supported_languages": null}, "macro.dbt.materialized_view_get_build_sql": {"name": "materialized_view_get_build_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialized_view_get_build_sql", "macro_sql": "{% macro materialized_view_get_build_sql(existing_relation, target_relation, backup_relation, intermediate_relation) %}\n\n    {% set full_refresh_mode = should_full_refresh() %}\n\n    -- determine the scenario we're in: create, full_refresh, alter, refresh data\n    {% if existing_relation is none %}\n        {% set build_sql = get_create_materialized_view_as_sql(target_relation, sql) %}\n    {% elif full_refresh_mode or not existing_relation.is_materialized_view %}\n        {% set build_sql = get_replace_sql(existing_relation, target_relation, sql) %}\n    {% else %}\n\n        -- get config options\n        {% set on_configuration_change = config.get('on_configuration_change') %}\n        {% set configuration_changes = get_materialized_view_configuration_changes(existing_relation, config) %}\n\n        {% if configuration_changes is none %}\n            {% set build_sql = refresh_materialized_view(target_relation) %}\n\n        {% elif on_configuration_change == 'apply' %}\n            {% set build_sql = get_alter_materialized_view_as_sql(target_relation, configuration_changes, sql, existing_relation, backup_relation, intermediate_relation) %}\n        {% elif on_configuration_change == 'continue' %}\n            {% set build_sql = '' %}\n            {{ exceptions.warn(\"Configuration changes were identified and `on_configuration_change` was set to `continue` for `\" ~ target_relation ~ \"`\") }}\n        {% elif on_configuration_change == 'fail' %}\n            {{ exceptions.raise_fail_fast_error(\"Configuration changes were identified and `on_configuration_change` was set to `fail` for `\" ~ target_relation ~ \"`\") }}\n\n        {% else %}\n            -- this only happens if the user provides a value other than `apply`, 'skip', 'fail'\n            {{ exceptions.raise_compiler_error(\"Unexpected configuration scenario\") }}\n\n        {% endif %}\n\n    {% endif %}\n\n    {% do return(build_sql) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.should_full_refresh", "macro.dbt.get_create_materialized_view_as_sql", "macro.dbt.get_replace_sql", "macro.dbt.get_materialized_view_configuration_changes", "macro.dbt.refresh_materialized_view", "macro.dbt.get_alter_materialized_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.296279, "supported_languages": null}, "macro.dbt.materialized_view_execute_no_op": {"name": "materialized_view_execute_no_op", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialized_view_execute_no_op", "macro_sql": "{% macro materialized_view_execute_no_op(target_relation) %}\n    {% do store_raw_result(\n        name=\"main\",\n        message=\"skip \" ~ target_relation,\n        code=\"skip\",\n        rows_affected=\"-1\"\n    ) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.296524, "supported_languages": null}, "macro.dbt.materialized_view_execute_build_sql": {"name": "materialized_view_execute_build_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/materialized_view.sql", "original_file_path": "macros/materializations/models/materialized_view.sql", "unique_id": "macro.dbt.materialized_view_execute_build_sql", "macro_sql": "{% macro materialized_view_execute_build_sql(build_sql, existing_relation, target_relation, post_hooks) %}\n\n    -- `BEGIN` happens here:\n    {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n    {% set grant_config = config.get('grants') %}\n\n    {% call statement(name=\"main\") %}\n        {{ build_sql }}\n    {% endcall %}\n\n    {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n    {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n    {% do persist_docs(target_relation, model) %}\n\n    {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n    {{ adapter.commit() }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.297158, "supported_languages": null}, "macro.dbt.materialization_view_default": {"name": "materialization_view_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/view.sql", "original_file_path": "macros/materializations/models/view.sql", "unique_id": "macro.dbt.materialization_view_default", "macro_sql": "{%- materialization view, default -%}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='view') -%}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n     This relation (probably) doesn't exist yet. If it does exist, it's a leftover from\n     a previous run, and we're going to try to drop it immediately. At the end of this\n     materialization, we're going to rename the \"existing_relation\" to this identifier,\n     and then we're going to drop it. In order to make sure we run the correct one of:\n       - drop view ...\n       - drop table ...\n\n     We need to set the type of this relation to be the type of the existing_relation, if it exists,\n     or else \"view\" as a sane default if it does not. Note that if the existing_relation does not\n     exist, then there is nothing to move out of the way and subsequentally drop. In that case,\n     this relation will be effectively unused.\n  */\n  {%- set backup_relation_type = 'view' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_view_as_sql(intermediate_relation, sql) }}\n  {%- endcall %}\n\n  -- cleanup\n  -- move the existing view out of the way\n  {% if existing_relation is not none %}\n     /* Do the equivalent of rename_if_exists. 'existing_relation' could have been dropped\n        since the variable was first set. */\n    {% set existing_relation = load_cached_relation(existing_relation) %}\n    {% if existing_relation is not none %}\n        {{ adapter.rename_relation(existing_relation, backup_relation) }}\n    {% endif %}\n  {% endif %}\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {{ adapter.commit() }}\n\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization -%}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.run_hooks", "macro.dbt.drop_relation_if_exists", "macro.dbt.statement", "macro.dbt.get_create_view_as_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.300074, "supported_languages": ["sql"]}, "macro.dbt.materialization_table_default": {"name": "materialization_table_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/table.sql", "original_file_path": "macros/materializations/models/table.sql", "unique_id": "macro.dbt.materialization_table_default", "macro_sql": "{% materialization table, default %}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') %}\n  {%- set intermediate_relation =  make_intermediate_relation(target_relation) -%}\n  -- the intermediate_relation should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation) -%}\n  /*\n      See ../view/view.sql for more information about this relation.\n  */\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n  -- as above, the backup_relation should not already exist\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n  -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n\n  -- drop the temp relations if they exist already in the database\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_table_as_sql(False, intermediate_relation, sql) }}\n  {%- endcall %}\n\n  -- cleanup\n  {% if existing_relation is not none %}\n     /* Do the equivalent of rename_if_exists. 'existing_relation' could have been dropped\n        since the variable was first set. */\n    {% set existing_relation = load_cached_relation(existing_relation) %}\n    {% if existing_relation is not none %}\n        {{ adapter.rename_relation(existing_relation, backup_relation) }}\n    {% endif %}\n  {% endif %}\n\n  {{ adapter.rename_relation(intermediate_relation, target_relation) }}\n\n  {% do create_indexes(target_relation) %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  -- finally, drop the existing/backup relation after the commit\n  {{ drop_relation_if_exists(backup_relation) }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.statement", "macro.dbt.get_create_table_as_sql", "macro.dbt.create_indexes", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3028, "supported_languages": ["sql"]}, "macro.dbt.get_quoted_csv": {"name": "get_quoted_csv", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.get_quoted_csv", "macro_sql": "{% macro get_quoted_csv(column_names) %}\n\n    {% set quoted = [] %}\n    {% for col in column_names -%}\n        {%- do quoted.append(adapter.quote(col)) -%}\n    {%- endfor %}\n\n    {%- set dest_cols_csv = quoted | join(', ') -%}\n    {{ return(dest_cols_csv) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.304387, "supported_languages": null}, "macro.dbt.diff_columns": {"name": "diff_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.diff_columns", "macro_sql": "{% macro diff_columns(source_columns, target_columns) %}\n\n  {% set result = [] %}\n  {% set source_names = source_columns | map(attribute = 'column') | list %}\n  {% set target_names = target_columns | map(attribute = 'column') | list %}\n\n   {# --check whether the name attribute exists in the target - this does not perform a data type check #}\n   {% for sc in source_columns %}\n     {% if sc.name not in target_names %}\n        {{ result.append(sc) }}\n     {% endif %}\n   {% endfor %}\n\n  {{ return(result) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.304915, "supported_languages": null}, "macro.dbt.diff_column_data_types": {"name": "diff_column_data_types", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.diff_column_data_types", "macro_sql": "{% macro diff_column_data_types(source_columns, target_columns) %}\n\n  {% set result = [] %}\n  {% for sc in source_columns %}\n    {% set tc = target_columns | selectattr(\"name\", \"equalto\", sc.name) | list | first %}\n    {% if tc %}\n      {% if sc.data_type != tc.data_type and not sc.can_expand_to(other_column=tc) %}\n        {{ result.append( { 'column_name': tc.name, 'new_type': sc.data_type } ) }}\n      {% endif %}\n    {% endif %}\n  {% endfor %}\n\n  {{ return(result) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3055842, "supported_languages": null}, "macro.dbt.get_merge_update_columns": {"name": "get_merge_update_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.get_merge_update_columns", "macro_sql": "{% macro get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) %}\n  {{ return(adapter.dispatch('get_merge_update_columns', 'dbt')(merge_update_columns, merge_exclude_columns, dest_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_merge_update_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.305813, "supported_languages": null}, "macro.dbt.default__get_merge_update_columns": {"name": "default__get_merge_update_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/column_helpers.sql", "original_file_path": "macros/materializations/models/incremental/column_helpers.sql", "unique_id": "macro.dbt.default__get_merge_update_columns", "macro_sql": "{% macro default__get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) %}\n  {%- set default_cols = dest_columns | map(attribute=\"quoted\") | list -%}\n\n  {%- if merge_update_columns and merge_exclude_columns -%}\n    {{ exceptions.raise_compiler_error(\n        'Model cannot specify merge_update_columns and merge_exclude_columns. Please update model to use only one config'\n    )}}\n  {%- elif merge_update_columns -%}\n    {%- set update_columns = merge_update_columns -%}\n  {%- elif merge_exclude_columns -%}\n    {%- set update_columns = [] -%}\n    {%- for column in dest_columns -%}\n      {% if column.column | lower not in merge_exclude_columns | map(\"lower\") | list %}\n        {%- do update_columns.append(column.quoted) -%}\n      {% endif %}\n    {%- endfor -%}\n  {%- else -%}\n    {%- set update_columns = default_cols -%}\n  {%- endif -%}\n\n  {{ return(update_columns) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.306525, "supported_languages": null}, "macro.dbt.get_merge_sql": {"name": "get_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_merge_sql", "macro_sql": "{% macro get_merge_sql(target, source, unique_key, dest_columns, incremental_predicates=none) -%}\n   -- back compat for old kwarg name\n  {% set incremental_predicates = kwargs.get('predicates', incremental_predicates) %}\n  {{ adapter.dispatch('get_merge_sql', 'dbt')(target, source, unique_key, dest_columns, incremental_predicates) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3130748, "supported_languages": null}, "macro.dbt.default__get_merge_sql": {"name": "default__get_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_merge_sql", "macro_sql": "{% macro default__get_merge_sql(target, source, unique_key, dest_columns, incremental_predicates=none) -%}\n    {%- set predicates = [] if incremental_predicates is none else [] + incremental_predicates -%}\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n    {%- set merge_update_columns = config.get('merge_update_columns') -%}\n    {%- set merge_exclude_columns = config.get('merge_exclude_columns') -%}\n    {%- set update_columns = get_merge_update_columns(merge_update_columns, merge_exclude_columns, dest_columns) -%}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {% if unique_key %}\n        {% if unique_key is sequence and unique_key is not mapping and unique_key is not string %}\n            {% for key in unique_key %}\n                {% set this_key_match %}\n                    DBT_INTERNAL_SOURCE.{{ key }} = DBT_INTERNAL_DEST.{{ key }}\n                {% endset %}\n                {% do predicates.append(this_key_match) %}\n            {% endfor %}\n        {% else %}\n            {% set unique_key_match %}\n                DBT_INTERNAL_SOURCE.{{ unique_key }} = DBT_INTERNAL_DEST.{{ unique_key }}\n            {% endset %}\n            {% do predicates.append(unique_key_match) %}\n        {% endif %}\n    {% else %}\n        {% do predicates.append('FALSE') %}\n    {% endif %}\n\n    {{ sql_header if sql_header is not none }}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n        using {{ source }} as DBT_INTERNAL_SOURCE\n        on {{\"(\" ~ predicates | join(\") and (\") ~ \")\"}}\n\n    {% if unique_key %}\n    when matched then update set\n        {% for column_name in update_columns -%}\n            {{ column_name }} = DBT_INTERNAL_SOURCE.{{ column_name }}\n            {%- if not loop.last %}, {%- endif %}\n        {%- endfor %}\n    {% endif %}\n\n    when not matched then insert\n        ({{ dest_cols_csv }})\n    values\n        ({{ dest_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv", "macro.dbt.get_merge_update_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.314634, "supported_languages": null}, "macro.dbt.get_delete_insert_merge_sql": {"name": "get_delete_insert_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_delete_insert_merge_sql", "macro_sql": "{% macro get_delete_insert_merge_sql(target, source, unique_key, dest_columns, incremental_predicates) -%}\n  {{ adapter.dispatch('get_delete_insert_merge_sql', 'dbt')(target, source, unique_key, dest_columns, incremental_predicates) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_delete_insert_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.314893, "supported_languages": null}, "macro.dbt.default__get_delete_insert_merge_sql": {"name": "default__get_delete_insert_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_delete_insert_merge_sql", "macro_sql": "{% macro default__get_delete_insert_merge_sql(target, source, unique_key, dest_columns, incremental_predicates) -%}\n\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n\n    {% if unique_key %}\n        {% if unique_key is sequence and unique_key is not string %}\n            delete from {{target }}\n            using {{ source }}\n            where (\n                {% for key in unique_key %}\n                    {{ source }}.{{ key }} = {{ target }}.{{ key }}\n                    {{ \"and \" if not loop.last}}\n                {% endfor %}\n                {% if incremental_predicates %}\n                    {% for predicate in incremental_predicates %}\n                        and {{ predicate }}\n                    {% endfor %}\n                {% endif %}\n            );\n        {% else %}\n            delete from {{ target }}\n            where (\n                {{ unique_key }}) in (\n                select ({{ unique_key }})\n                from {{ source }}\n            )\n            {%- if incremental_predicates %}\n                {% for predicate in incremental_predicates %}\n                    and {{ predicate }}\n                {% endfor %}\n            {%- endif -%};\n\n        {% endif %}\n    {% endif %}\n\n    insert into {{ target }} ({{ dest_cols_csv }})\n    (\n        select {{ dest_cols_csv }}\n        from {{ source }}\n    )\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3158798, "supported_languages": null}, "macro.dbt.get_insert_overwrite_merge_sql": {"name": "get_insert_overwrite_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.get_insert_overwrite_merge_sql", "macro_sql": "{% macro get_insert_overwrite_merge_sql(target, source, dest_columns, predicates, include_sql_header=false) -%}\n  {{ adapter.dispatch('get_insert_overwrite_merge_sql', 'dbt')(target, source, dest_columns, predicates, include_sql_header) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_insert_overwrite_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3161511, "supported_languages": null}, "macro.dbt.default__get_insert_overwrite_merge_sql": {"name": "default__get_insert_overwrite_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/merge.sql", "original_file_path": "macros/materializations/models/incremental/merge.sql", "unique_id": "macro.dbt.default__get_insert_overwrite_merge_sql", "macro_sql": "{% macro default__get_insert_overwrite_merge_sql(target, source, dest_columns, predicates, include_sql_header) -%}\n    {#-- The only time include_sql_header is True: --#}\n    {#-- BigQuery + insert_overwrite strategy + \"static\" partitions config --#}\n    {#-- We should consider including the sql header at the materialization level instead --#}\n\n    {%- set predicates = [] if predicates is none else [] + predicates -%}\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n    {%- set sql_header = config.get('sql_header', none) -%}\n\n    {{ sql_header if sql_header is not none and include_sql_header }}\n\n    merge into {{ target }} as DBT_INTERNAL_DEST\n        using {{ source }} as DBT_INTERNAL_SOURCE\n        on FALSE\n\n    when not matched by source\n        {% if predicates %} and {{ predicates | join(' and ') }} {% endif %}\n        then delete\n\n    when not matched then insert\n        ({{ dest_cols_csv }})\n    values\n        ({{ dest_cols_csv }})\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3167958, "supported_languages": null}, "macro.dbt.is_incremental": {"name": "is_incremental", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/is_incremental.sql", "original_file_path": "macros/materializations/models/incremental/is_incremental.sql", "unique_id": "macro.dbt.is_incremental", "macro_sql": "{% macro is_incremental() %}\n    {#-- do not run introspective queries in parsing #}\n    {% if not execute %}\n        {{ return(False) }}\n    {% else %}\n        {% set relation = adapter.get_relation(this.database, this.schema, this.table) %}\n        {{ return(relation is not none\n                  and relation.type == 'table'\n                  and model.config.materialized == 'incremental'\n                  and not should_full_refresh()) }}\n    {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.should_full_refresh"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.31741, "supported_languages": null}, "macro.dbt.get_incremental_append_sql": {"name": "get_incremental_append_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_append_sql", "macro_sql": "{% macro get_incremental_append_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_append_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_append_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3182871, "supported_languages": null}, "macro.dbt.default__get_incremental_append_sql": {"name": "default__get_incremental_append_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_append_sql", "macro_sql": "{% macro default__get_incremental_append_sql(arg_dict) %}\n\n  {% do return(get_insert_into_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"dest_columns\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_insert_into_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3185332, "supported_languages": null}, "macro.dbt.get_incremental_delete_insert_sql": {"name": "get_incremental_delete_insert_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_delete_insert_sql", "macro_sql": "{% macro get_incremental_delete_insert_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_delete_insert_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_delete_insert_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.31872, "supported_languages": null}, "macro.dbt.default__get_incremental_delete_insert_sql": {"name": "default__get_incremental_delete_insert_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_delete_insert_sql", "macro_sql": "{% macro default__get_incremental_delete_insert_sql(arg_dict) %}\n\n  {% do return(get_delete_insert_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"unique_key\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_delete_insert_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.319013, "supported_languages": null}, "macro.dbt.get_incremental_merge_sql": {"name": "get_incremental_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_merge_sql", "macro_sql": "{% macro get_incremental_merge_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_merge_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3192692, "supported_languages": null}, "macro.dbt.default__get_incremental_merge_sql": {"name": "default__get_incremental_merge_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_merge_sql", "macro_sql": "{% macro default__get_incremental_merge_sql(arg_dict) %}\n\n  {% do return(get_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"unique_key\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.319564, "supported_languages": null}, "macro.dbt.get_incremental_insert_overwrite_sql": {"name": "get_incremental_insert_overwrite_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_insert_overwrite_sql", "macro_sql": "{% macro get_incremental_insert_overwrite_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_insert_overwrite_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_incremental_insert_overwrite_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.319751, "supported_languages": null}, "macro.dbt.default__get_incremental_insert_overwrite_sql": {"name": "default__get_incremental_insert_overwrite_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_insert_overwrite_sql", "macro_sql": "{% macro default__get_incremental_insert_overwrite_sql(arg_dict) %}\n\n  {% do return(get_insert_overwrite_merge_sql(arg_dict[\"target_relation\"], arg_dict[\"temp_relation\"], arg_dict[\"dest_columns\"], arg_dict[\"incremental_predicates\"])) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_insert_overwrite_merge_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.320024, "supported_languages": null}, "macro.dbt.get_incremental_default_sql": {"name": "get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_incremental_default_sql", "macro_sql": "{% macro get_incremental_default_sql(arg_dict) %}\n\n  {{ return(adapter.dispatch('get_incremental_default_sql', 'dbt')(arg_dict)) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_incremental_default_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3202062, "supported_languages": null}, "macro.dbt.default__get_incremental_default_sql": {"name": "default__get_incremental_default_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.default__get_incremental_default_sql", "macro_sql": "{% macro default__get_incremental_default_sql(arg_dict) %}\n\n  {% do return(get_incremental_append_sql(arg_dict)) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_incremental_append_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.320364, "supported_languages": null}, "macro.dbt.get_insert_into_sql": {"name": "get_insert_into_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/strategies.sql", "original_file_path": "macros/materializations/models/incremental/strategies.sql", "unique_id": "macro.dbt.get_insert_into_sql", "macro_sql": "{% macro get_insert_into_sql(target_relation, temp_relation, dest_columns) %}\n\n    {%- set dest_cols_csv = get_quoted_csv(dest_columns | map(attribute=\"name\")) -%}\n\n    insert into {{ target_relation }} ({{ dest_cols_csv }})\n    (\n        select {{ dest_cols_csv }}\n        from {{ temp_relation }}\n    )\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_quoted_csv"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3206358, "supported_languages": null}, "macro.dbt.materialization_incremental_default": {"name": "materialization_incremental_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/incremental.sql", "original_file_path": "macros/materializations/models/incremental/incremental.sql", "unique_id": "macro.dbt.materialization_incremental_default", "macro_sql": "{% materialization incremental, default -%}\n\n  -- relations\n  {%- set existing_relation = load_cached_relation(this) -%}\n  {%- set target_relation = this.incorporate(type='table') -%}\n  {%- set temp_relation = make_temp_relation(target_relation)-%}\n  {%- set intermediate_relation = make_intermediate_relation(target_relation)-%}\n  {%- set backup_relation_type = 'table' if existing_relation is none else existing_relation.type -%}\n  {%- set backup_relation = make_backup_relation(target_relation, backup_relation_type) -%}\n\n  -- configs\n  {%- set unique_key = config.get('unique_key') -%}\n  {%- set full_refresh_mode = (should_full_refresh()  or existing_relation.is_view) -%}\n  {%- set on_schema_change = incremental_validate_on_schema_change(config.get('on_schema_change'), default='ignore') -%}\n\n  -- the temp_ and backup_ relations should not already exist in the database; get_relation\n  -- will return None in that case. Otherwise, we get a relation that we can drop\n  -- later, before we try to use this name for the current operation. This has to happen before\n  -- BEGIN, in a separate transaction\n  {%- set preexisting_intermediate_relation = load_cached_relation(intermediate_relation)-%}\n  {%- set preexisting_backup_relation = load_cached_relation(backup_relation) -%}\n   -- grab current tables grants config for comparision later on\n  {% set grant_config = config.get('grants') %}\n  {{ drop_relation_if_exists(preexisting_intermediate_relation) }}\n  {{ drop_relation_if_exists(preexisting_backup_relation) }}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  {% set to_drop = [] %}\n\n  {% if existing_relation is none %}\n      {% set build_sql = get_create_table_as_sql(False, target_relation, sql) %}\n  {% elif full_refresh_mode %}\n      {% set build_sql = get_create_table_as_sql(False, intermediate_relation, sql) %}\n      {% set need_swap = true %}\n  {% else %}\n    {% do run_query(get_create_table_as_sql(True, temp_relation, sql)) %}\n    {% do adapter.expand_target_column_types(\n             from_relation=temp_relation,\n             to_relation=target_relation) %}\n    {#-- Process schema changes. Returns dict of changes if successful. Use source columns for upserting/merging --#}\n    {% set dest_columns = process_schema_changes(on_schema_change, temp_relation, existing_relation) %}\n    {% if not dest_columns %}\n      {% set dest_columns = adapter.get_columns_in_relation(existing_relation) %}\n    {% endif %}\n\n    {#-- Get the incremental_strategy, the macro to use for the strategy, and build the sql --#}\n    {% set incremental_strategy = config.get('incremental_strategy') or 'default' %}\n    {% set incremental_predicates = config.get('predicates', none) or config.get('incremental_predicates', none) %}\n    {% set strategy_sql_macro_func = adapter.get_incremental_strategy_macro(context, incremental_strategy) %}\n    {% set strategy_arg_dict = ({'target_relation': target_relation, 'temp_relation': temp_relation, 'unique_key': unique_key, 'dest_columns': dest_columns, 'incremental_predicates': incremental_predicates }) %}\n    {% set build_sql = strategy_sql_macro_func(strategy_arg_dict) %}\n\n  {% endif %}\n\n  {% call statement(\"main\") %}\n      {{ build_sql }}\n  {% endcall %}\n\n  {% if need_swap %}\n      {% do adapter.rename_relation(target_relation, backup_relation) %}\n      {% do adapter.rename_relation(intermediate_relation, target_relation) %}\n      {% do to_drop.append(backup_relation) %}\n  {% endif %}\n\n  {% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if existing_relation is none or existing_relation.is_view or should_full_refresh() %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {% do adapter.commit() %}\n\n  {% for rel in to_drop %}\n      {% do adapter.drop_relation(rel) %}\n  {% endfor %}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{%- endmaterialization %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.make_temp_relation", "macro.dbt.make_intermediate_relation", "macro.dbt.make_backup_relation", "macro.dbt.should_full_refresh", "macro.dbt.incremental_validate_on_schema_change", "macro.dbt.drop_relation_if_exists", "macro.dbt.run_hooks", "macro.dbt.get_create_table_as_sql", "macro.dbt.run_query", "macro.dbt.process_schema_changes", "macro.dbt.statement", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3254771, "supported_languages": ["sql"]}, "macro.dbt.incremental_validate_on_schema_change": {"name": "incremental_validate_on_schema_change", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.incremental_validate_on_schema_change", "macro_sql": "{% macro incremental_validate_on_schema_change(on_schema_change, default='ignore') %}\n\n   {% if on_schema_change not in ['sync_all_columns', 'append_new_columns', 'fail', 'ignore'] %}\n\n     {% set log_message = 'Invalid value for on_schema_change (%s) specified. Setting default value of %s.' % (on_schema_change, default) %}\n     {% do log(log_message) %}\n\n     {{ return(default) }}\n\n   {% else %}\n\n     {{ return(on_schema_change) }}\n\n   {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.331095, "supported_languages": null}, "macro.dbt.check_for_schema_changes": {"name": "check_for_schema_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.check_for_schema_changes", "macro_sql": "{% macro check_for_schema_changes(source_relation, target_relation) %}\n\n  {% set schema_changed = False %}\n\n  {%- set source_columns = adapter.get_columns_in_relation(source_relation) -%}\n  {%- set target_columns = adapter.get_columns_in_relation(target_relation) -%}\n  {%- set source_not_in_target = diff_columns(source_columns, target_columns) -%}\n  {%- set target_not_in_source = diff_columns(target_columns, source_columns) -%}\n\n  {% set new_target_types = diff_column_data_types(source_columns, target_columns) %}\n\n  {% if source_not_in_target != [] %}\n    {% set schema_changed = True %}\n  {% elif target_not_in_source != [] or new_target_types != [] %}\n    {% set schema_changed = True %}\n  {% elif new_target_types != [] %}\n    {% set schema_changed = True %}\n  {% endif %}\n\n  {% set changes_dict = {\n    'schema_changed': schema_changed,\n    'source_not_in_target': source_not_in_target,\n    'target_not_in_source': target_not_in_source,\n    'source_columns': source_columns,\n    'target_columns': target_columns,\n    'new_target_types': new_target_types\n  } %}\n\n  {% set msg %}\n    In {{ target_relation }}:\n        Schema changed: {{ schema_changed }}\n        Source columns not in target: {{ source_not_in_target }}\n        Target columns not in source: {{ target_not_in_source }}\n        New column types: {{ new_target_types }}\n  {% endset %}\n\n  {% do log(msg) %}\n\n  {{ return(changes_dict) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.diff_columns", "macro.dbt.diff_column_data_types"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.332284, "supported_languages": null}, "macro.dbt.sync_column_schemas": {"name": "sync_column_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.sync_column_schemas", "macro_sql": "{% macro sync_column_schemas(on_schema_change, target_relation, schema_changes_dict) %}\n\n  {%- set add_to_target_arr = schema_changes_dict['source_not_in_target'] -%}\n\n  {%- if on_schema_change == 'append_new_columns'-%}\n     {%- if add_to_target_arr | length > 0 -%}\n       {%- do alter_relation_add_remove_columns(target_relation, add_to_target_arr, none) -%}\n     {%- endif -%}\n\n  {% elif on_schema_change == 'sync_all_columns' %}\n     {%- set remove_from_target_arr = schema_changes_dict['target_not_in_source'] -%}\n     {%- set new_target_types = schema_changes_dict['new_target_types'] -%}\n\n     {% if add_to_target_arr | length > 0 or remove_from_target_arr | length > 0 %}\n       {%- do alter_relation_add_remove_columns(target_relation, add_to_target_arr, remove_from_target_arr) -%}\n     {% endif %}\n\n     {% if new_target_types != [] %}\n       {% for ntt in new_target_types %}\n         {% set column_name = ntt['column_name'] %}\n         {% set new_type = ntt['new_type'] %}\n         {% do alter_column_type(target_relation, column_name, new_type) %}\n       {% endfor %}\n     {% endif %}\n\n  {% endif %}\n\n  {% set schema_change_message %}\n    In {{ target_relation }}:\n        Schema change approach: {{ on_schema_change }}\n        Columns added: {{ add_to_target_arr }}\n        Columns removed: {{ remove_from_target_arr }}\n        Data types changed: {{ new_target_types }}\n  {% endset %}\n\n  {% do log(schema_change_message) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.alter_relation_add_remove_columns", "macro.dbt.alter_column_type"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.33348, "supported_languages": null}, "macro.dbt.process_schema_changes": {"name": "process_schema_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/incremental/on_schema_change.sql", "original_file_path": "macros/materializations/models/incremental/on_schema_change.sql", "unique_id": "macro.dbt.process_schema_changes", "macro_sql": "{% macro process_schema_changes(on_schema_change, source_relation, target_relation) %}\n\n    {% if on_schema_change == 'ignore' %}\n\n     {{ return({}) }}\n\n    {% else %}\n\n      {% set schema_changes_dict = check_for_schema_changes(source_relation, target_relation) %}\n\n      {% if schema_changes_dict['schema_changed'] %}\n\n        {% if on_schema_change == 'fail' %}\n\n          {% set fail_msg %}\n              The source and target schemas on this incremental model are out of sync!\n              They can be reconciled in several ways:\n                - set the `on_schema_change` config to either append_new_columns or sync_all_columns, depending on your situation.\n                - Re-run the incremental model with `full_refresh: True` to update the target schema.\n                - update the schema manually and re-run the process.\n\n              Additional troubleshooting context:\n                 Source columns not in target: {{ schema_changes_dict['source_not_in_target'] }}\n                 Target columns not in source: {{ schema_changes_dict['target_not_in_source'] }}\n                 New column types: {{ schema_changes_dict['new_target_types'] }}\n          {% endset %}\n\n          {% do exceptions.raise_compiler_error(fail_msg) %}\n\n        {# -- unless we ignore, run the sync operation per the config #}\n        {% else %}\n\n          {% do sync_column_schemas(on_schema_change, target_relation, schema_changes_dict) %}\n\n        {% endif %}\n\n      {% endif %}\n\n      {{ return(schema_changes_dict['source_columns']) }}\n\n    {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.check_for_schema_changes", "macro.dbt.sync_column_schemas"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.334361, "supported_languages": null}, "macro.dbt.can_clone_table": {"name": "can_clone_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/clone/can_clone_table.sql", "original_file_path": "macros/materializations/models/clone/can_clone_table.sql", "unique_id": "macro.dbt.can_clone_table", "macro_sql": "{% macro can_clone_table() %}\n    {{ return(adapter.dispatch('can_clone_table', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__can_clone_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.334629, "supported_languages": null}, "macro.dbt.default__can_clone_table": {"name": "default__can_clone_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/clone/can_clone_table.sql", "original_file_path": "macros/materializations/models/clone/can_clone_table.sql", "unique_id": "macro.dbt.default__can_clone_table", "macro_sql": "{% macro default__can_clone_table() %}\n    {{ return(False) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.334752, "supported_languages": null}, "macro.dbt.create_or_replace_clone": {"name": "create_or_replace_clone", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/clone/create_or_replace_clone.sql", "original_file_path": "macros/materializations/models/clone/create_or_replace_clone.sql", "unique_id": "macro.dbt.create_or_replace_clone", "macro_sql": "{% macro create_or_replace_clone(this_relation, defer_relation) %}\n    {{ return(adapter.dispatch('create_or_replace_clone', 'dbt')(this_relation, defer_relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_or_replace_clone"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3350348, "supported_languages": null}, "macro.dbt.default__create_or_replace_clone": {"name": "default__create_or_replace_clone", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/clone/create_or_replace_clone.sql", "original_file_path": "macros/materializations/models/clone/create_or_replace_clone.sql", "unique_id": "macro.dbt.default__create_or_replace_clone", "macro_sql": "{% macro default__create_or_replace_clone(this_relation, defer_relation) %}\n    create or replace table {{ this_relation }} clone {{ defer_relation }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.33516, "supported_languages": null}, "macro.dbt.materialization_clone_default": {"name": "materialization_clone_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/models/clone/clone.sql", "original_file_path": "macros/materializations/models/clone/clone.sql", "unique_id": "macro.dbt.materialization_clone_default", "macro_sql": "{%- materialization clone, default -%}\n\n  {%- set relations = {'relations': []} -%}\n\n  {%- if not defer_relation -%}\n      -- nothing to do\n      {{ log(\"No relation found in state manifest for \" ~ model.unique_id, info=True) }}\n      {{ return(relations) }}\n  {%- endif -%}\n\n  {%- set existing_relation = load_cached_relation(this) -%}\n\n  {%- if existing_relation and not flags.FULL_REFRESH -%}\n      -- noop!\n      {{ log(\"Relation \" ~ existing_relation ~ \" already exists\", info=True) }}\n      {{ return(relations) }}\n  {%- endif -%}\n\n  {%- set other_existing_relation = load_cached_relation(defer_relation) -%}\n\n  -- If this is a database that can do zero-copy cloning of tables, and the other relation is a table, then this will be a table\n  -- Otherwise, this will be a view\n\n  {% set can_clone_table = can_clone_table() %}\n\n  {%- if other_existing_relation and other_existing_relation.type == 'table' and can_clone_table -%}\n\n      {%- set target_relation = this.incorporate(type='table') -%}\n      {% if existing_relation is not none and not existing_relation.is_table %}\n        {{ log(\"Dropping relation \" ~ existing_relation ~ \" because it is of type \" ~ existing_relation.type) }}\n        {{ drop_relation_if_exists(existing_relation) }}\n      {% endif %}\n\n      -- as a general rule, data platforms that can clone tables can also do atomic 'create or replace'\n      {% call statement('main') %}\n          {% if target_relation and defer_relation and target_relation == defer_relation %}\n              {{ log(\"Target relation and defer relation are the same, skipping clone for relation: \" ~ target_relation) }}\n          {% else %}\n              {{ create_or_replace_clone(target_relation, defer_relation) }}\n          {% endif %}\n\n      {% endcall %}\n\n      {% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}\n      {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n      {% do persist_docs(target_relation, model) %}\n\n      {{ return({'relations': [target_relation]}) }}\n\n  {%- else -%}\n\n      {%- set target_relation = this.incorporate(type='view') -%}\n\n      -- reuse the view materialization\n      -- TODO: support actual dispatch for materialization macros\n      -- Tracking ticket: https://github.com/dbt-labs/dbt-core/issues/7799\n      {% set search_name = \"materialization_view_\" ~ adapter.type() %}\n      {% if not search_name in context %}\n          {% set search_name = \"materialization_view_default\" %}\n      {% endif %}\n      {% set materialization_macro = context[search_name] %}\n      {% set relations = materialization_macro() %}\n      {{ return(relations) }}\n\n  {%- endif -%}\n\n{%- endmaterialization -%}", "depends_on": {"macros": ["macro.dbt.load_cached_relation", "macro.dbt.can_clone_table", "macro.dbt.drop_relation_if_exists", "macro.dbt.statement", "macro.dbt.create_or_replace_clone", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.33875, "supported_languages": ["sql"]}, "macro.dbt.materialization_seed_default": {"name": "materialization_seed_default", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/seed.sql", "original_file_path": "macros/materializations/seeds/seed.sql", "unique_id": "macro.dbt.materialization_seed_default", "macro_sql": "{% materialization seed, default %}\n\n  {%- set identifier = model['alias'] -%}\n  {%- set full_refresh_mode = (should_full_refresh()) -%}\n\n  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}\n\n  {%- set exists_as_table = (old_relation is not none and old_relation.is_table) -%}\n  {%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}\n\n  {%- set grant_config = config.get('grants') -%}\n  {%- set agate_table = load_agate_table() -%}\n  -- grab current tables grants config for comparison later on\n\n  {%- do store_result('agate_table', response='OK', agate_table=agate_table) -%}\n\n  {{ run_hooks(pre_hooks, inside_transaction=False) }}\n\n  -- `BEGIN` happens here:\n  {{ run_hooks(pre_hooks, inside_transaction=True) }}\n\n  -- build model\n  {% set create_table_sql = \"\" %}\n  {% if exists_as_view %}\n    {{ exceptions.raise_compiler_error(\"Cannot seed to '{}', it is a view\".format(old_relation)) }}\n  {% elif exists_as_table %}\n    {% set create_table_sql = reset_csv_table(model, full_refresh_mode, old_relation, agate_table) %}\n  {% else %}\n    {% set create_table_sql = create_csv_table(model, agate_table) %}\n  {% endif %}\n\n  {% set code = 'CREATE' if full_refresh_mode else 'INSERT' %}\n  {% set rows_affected = (agate_table.rows | length) %}\n  {% set sql = load_csv_rows(model, agate_table) %}\n\n  {% call noop_statement('main', code ~ ' ' ~ rows_affected, code, rows_affected) %}\n    {{ get_csv_sql(create_table_sql, sql) }};\n  {% endcall %}\n\n  {% set target_relation = this.incorporate(type='table') %}\n\n  {% set should_revoke = should_revoke(old_relation, full_refresh_mode) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {% do persist_docs(target_relation, model) %}\n\n  {% if full_refresh_mode or not exists_as_table %}\n    {% do create_indexes(target_relation) %}\n  {% endif %}\n\n  {{ run_hooks(post_hooks, inside_transaction=True) }}\n\n  -- `COMMIT` happens here\n  {{ adapter.commit() }}\n\n  {{ run_hooks(post_hooks, inside_transaction=False) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmaterialization %}", "depends_on": {"macros": ["macro.dbt.should_full_refresh", "macro.dbt.run_hooks", "macro.dbt.reset_csv_table", "macro.dbt.create_csv_table", "macro.dbt.load_csv_rows", "macro.dbt.noop_statement", "macro.dbt.get_csv_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants", "macro.dbt.persist_docs", "macro.dbt.create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.341901, "supported_languages": ["sql"]}, "macro.dbt.create_csv_table": {"name": "create_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.create_csv_table", "macro_sql": "{% macro create_csv_table(model, agate_table) -%}\n  {{ adapter.dispatch('create_csv_table', 'dbt')(model, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.346889, "supported_languages": null}, "macro.dbt.default__create_csv_table": {"name": "default__create_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__create_csv_table", "macro_sql": "{% macro default__create_csv_table(model, agate_table) %}\n  {%- set column_override = model['config'].get('column_types', {}) -%}\n  {%- set quote_seed_column = model['config'].get('quote_columns', None) -%}\n\n  {% set sql %}\n    create table {{ this.render() }} (\n        {%- for col_name in agate_table.column_names -%}\n            {%- set inferred_type = adapter.convert_type(agate_table, loop.index0) -%}\n            {%- set type = column_override.get(col_name, inferred_type) -%}\n            {%- set column_name = (col_name | string) -%}\n            {{ adapter.quote_seed_column(column_name, quote_seed_column) }} {{ type }} {%- if not loop.last -%}, {%- endif -%}\n        {%- endfor -%}\n    )\n  {% endset %}\n\n  {% call statement('_') -%}\n    {{ sql }}\n  {%- endcall %}\n\n  {{ return(sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.347757, "supported_languages": null}, "macro.dbt.reset_csv_table": {"name": "reset_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.reset_csv_table", "macro_sql": "{% macro reset_csv_table(model, full_refresh, old_relation, agate_table) -%}\n  {{ adapter.dispatch('reset_csv_table', 'dbt')(model, full_refresh, old_relation, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__reset_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.348011, "supported_languages": null}, "macro.dbt.default__reset_csv_table": {"name": "default__reset_csv_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__reset_csv_table", "macro_sql": "{% macro default__reset_csv_table(model, full_refresh, old_relation, agate_table) %}\n    {% set sql = \"\" %}\n    {% if full_refresh %}\n        {{ adapter.drop_relation(old_relation) }}\n        {% set sql = create_csv_table(model, agate_table) %}\n    {% else %}\n        {{ adapter.truncate_relation(old_relation) }}\n        {% set sql = \"truncate table \" ~ old_relation %}\n    {% endif %}\n\n    {{ return(sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_csv_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.34848, "supported_languages": null}, "macro.dbt.get_csv_sql": {"name": "get_csv_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_csv_sql", "macro_sql": "{% macro get_csv_sql(create_or_truncate_sql, insert_sql) %}\n    {{ adapter.dispatch('get_csv_sql', 'dbt')(create_or_truncate_sql, insert_sql) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_csv_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.348659, "supported_languages": null}, "macro.dbt.default__get_csv_sql": {"name": "default__get_csv_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_csv_sql", "macro_sql": "{% macro default__get_csv_sql(create_or_truncate_sql, insert_sql) %}\n    {{ create_or_truncate_sql }};\n    -- dbt seed --\n    {{ insert_sql }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3488052, "supported_languages": null}, "macro.dbt.get_binding_char": {"name": "get_binding_char", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_binding_char", "macro_sql": "{% macro get_binding_char() -%}\n  {{ adapter.dispatch('get_binding_char', 'dbt')() }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.348948, "supported_languages": null}, "macro.dbt.default__get_binding_char": {"name": "default__get_binding_char", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_binding_char", "macro_sql": "{% macro default__get_binding_char() %}\n  {{ return('%s') }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.34906, "supported_languages": null}, "macro.dbt.get_batch_size": {"name": "get_batch_size", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_batch_size", "macro_sql": "{% macro get_batch_size() -%}\n  {{ return(adapter.dispatch('get_batch_size', 'dbt')()) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_batch_size"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.349211, "supported_languages": null}, "macro.dbt.default__get_batch_size": {"name": "default__get_batch_size", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__get_batch_size", "macro_sql": "{% macro default__get_batch_size() %}\n  {{ return(10000) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.349329, "supported_languages": null}, "macro.dbt.get_seed_column_quoted_csv": {"name": "get_seed_column_quoted_csv", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.get_seed_column_quoted_csv", "macro_sql": "{% macro get_seed_column_quoted_csv(model, column_names) %}\n  {%- set quote_seed_column = model['config'].get('quote_columns', None) -%}\n    {% set quoted = [] %}\n    {% for col in column_names -%}\n        {%- do quoted.append(adapter.quote_seed_column(col, quote_seed_column)) -%}\n    {%- endfor %}\n\n    {%- set dest_cols_csv = quoted | join(', ') -%}\n    {{ return(dest_cols_csv) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3498209, "supported_languages": null}, "macro.dbt.load_csv_rows": {"name": "load_csv_rows", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.load_csv_rows", "macro_sql": "{% macro load_csv_rows(model, agate_table) -%}\n  {{ adapter.dispatch('load_csv_rows', 'dbt')(model, agate_table) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__load_csv_rows"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.349995, "supported_languages": null}, "macro.dbt.default__load_csv_rows": {"name": "default__load_csv_rows", "resource_type": "macro", "package_name": "dbt", "path": "macros/materializations/seeds/helpers.sql", "original_file_path": "macros/materializations/seeds/helpers.sql", "unique_id": "macro.dbt.default__load_csv_rows", "macro_sql": "{% macro default__load_csv_rows(model, agate_table) %}\n\n  {% set batch_size = get_batch_size() %}\n\n  {% set cols_sql = get_seed_column_quoted_csv(model, agate_table.column_names) %}\n  {% set bindings = [] %}\n\n  {% set statements = [] %}\n\n  {% for chunk in agate_table.rows | batch(batch_size) %}\n      {% set bindings = [] %}\n\n      {% for row in chunk %}\n          {% do bindings.extend(row) %}\n      {% endfor %}\n\n      {% set sql %}\n          insert into {{ this.render() }} ({{ cols_sql }}) values\n          {% for row in chunk -%}\n              ({%- for column in agate_table.column_names -%}\n                  {{ get_binding_char() }}\n                  {%- if not loop.last%},{%- endif %}\n              {%- endfor -%})\n              {%- if not loop.last%},{%- endif %}\n          {%- endfor %}\n      {% endset %}\n\n      {% do adapter.add_query(sql, bindings=bindings, abridge_sql_log=True) %}\n\n      {% if loop.index0 == 0 %}\n          {% do statements.append(sql) %}\n      {% endif %}\n  {% endfor %}\n\n  {# Return SQL so we can render it out into the compiled files #}\n  {{ return(statements[0]) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_batch_size", "macro.dbt.get_seed_column_quoted_csv", "macro.dbt.get_binding_char"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3512099, "supported_languages": null}, "macro.dbt.generate_alias_name": {"name": "generate_alias_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_alias.sql", "original_file_path": "macros/get_custom_name/get_custom_alias.sql", "unique_id": "macro.dbt.generate_alias_name", "macro_sql": "{% macro generate_alias_name(custom_alias_name=none, node=none) -%}\n    {% do return(adapter.dispatch('generate_alias_name', 'dbt')(custom_alias_name, node)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_alias_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3516212, "supported_languages": null}, "macro.dbt.default__generate_alias_name": {"name": "default__generate_alias_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_alias.sql", "original_file_path": "macros/get_custom_name/get_custom_alias.sql", "unique_id": "macro.dbt.default__generate_alias_name", "macro_sql": "{% macro default__generate_alias_name(custom_alias_name=none, node=none) -%}\n\n    {%- if custom_alias_name -%}\n\n        {{ custom_alias_name | trim }}\n\n    {%- elif node.version -%}\n\n        {{ return(node.name ~ \"_v\" ~ (node.version | replace(\".\", \"_\"))) }}\n\n    {%- else -%}\n\n        {{ node.name }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.351978, "supported_languages": null}, "macro.dbt.generate_schema_name": {"name": "generate_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.generate_schema_name", "macro_sql": "{% macro generate_schema_name(custom_schema_name=none, node=none) -%}\n    {{ return(adapter.dispatch('generate_schema_name', 'dbt')(custom_schema_name, node)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_schema_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.352462, "supported_languages": null}, "macro.dbt.default__generate_schema_name": {"name": "default__generate_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.default__generate_schema_name", "macro_sql": "{% macro default__generate_schema_name(custom_schema_name, node) -%}\n\n    {%- set default_schema = target.schema -%}\n    {%- if custom_schema_name is none -%}\n\n        {{ default_schema }}\n\n    {%- else -%}\n\n        {{ default_schema }}_{{ custom_schema_name | trim }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.352705, "supported_languages": null}, "macro.dbt.generate_schema_name_for_env": {"name": "generate_schema_name_for_env", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_schema.sql", "original_file_path": "macros/get_custom_name/get_custom_schema.sql", "unique_id": "macro.dbt.generate_schema_name_for_env", "macro_sql": "{% macro generate_schema_name_for_env(custom_schema_name, node) -%}\n\n    {%- set default_schema = target.schema -%}\n    {%- if target.name == 'prod' and custom_schema_name is not none -%}\n\n        {{ custom_schema_name | trim }}\n\n    {%- else -%}\n\n        {{ default_schema }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.352967, "supported_languages": null}, "macro.dbt.generate_database_name": {"name": "generate_database_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_database.sql", "original_file_path": "macros/get_custom_name/get_custom_database.sql", "unique_id": "macro.dbt.generate_database_name", "macro_sql": "{% macro generate_database_name(custom_database_name=none, node=none) -%}\n    {% do return(adapter.dispatch('generate_database_name', 'dbt')(custom_database_name, node)) %}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_database_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3533351, "supported_languages": null}, "macro.dbt.default__generate_database_name": {"name": "default__generate_database_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/get_custom_name/get_custom_database.sql", "original_file_path": "macros/get_custom_name/get_custom_database.sql", "unique_id": "macro.dbt.default__generate_database_name", "macro_sql": "{% macro default__generate_database_name(custom_database_name=none, node=none) -%}\n    {%- set default_database = target.database -%}\n    {%- if custom_database_name is none -%}\n\n        {{ default_database }}\n\n    {%- else -%}\n\n        {{ custom_database_name }}\n\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.353569, "supported_languages": null}, "macro.dbt.get_drop_sql": {"name": "get_drop_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop.sql", "original_file_path": "macros/relations/drop.sql", "unique_id": "macro.dbt.get_drop_sql", "macro_sql": "{%- macro get_drop_sql(relation) -%}\n    {{- log('Applying DROP to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_drop_sql', 'dbt')(relation) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_drop_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.354291, "supported_languages": null}, "macro.dbt.default__get_drop_sql": {"name": "default__get_drop_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop.sql", "original_file_path": "macros/relations/drop.sql", "unique_id": "macro.dbt.default__get_drop_sql", "macro_sql": "{%- macro default__get_drop_sql(relation) -%}\n\n    {%- if relation.is_view -%}\n        {{ drop_view(relation) }}\n\n    {%- elif relation.is_table -%}\n        {{ drop_table(relation) }}\n\n    {%- elif relation.is_materialized_view -%}\n        {{ drop_materialized_view(relation) }}\n\n    {%- else -%}\n        drop {{ relation.type }} if exists {{ relation }} cascade\n\n    {%- endif -%}\n\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.drop_view", "macro.dbt.drop_table", "macro.dbt.drop_materialized_view"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.354657, "supported_languages": null}, "macro.dbt.drop_relation": {"name": "drop_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop.sql", "original_file_path": "macros/relations/drop.sql", "unique_id": "macro.dbt.drop_relation", "macro_sql": "{% macro drop_relation(relation) -%}\n    {{ return(adapter.dispatch('drop_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__drop_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.354845, "supported_languages": null}, "macro.dbt.default__drop_relation": {"name": "default__drop_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop.sql", "original_file_path": "macros/relations/drop.sql", "unique_id": "macro.dbt.default__drop_relation", "macro_sql": "{% macro default__drop_relation(relation) -%}\n    {% call statement('drop_relation', auto_begin=False) -%}\n        {{ get_drop_sql(relation) }}\n    {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.get_drop_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.355039, "supported_languages": null}, "macro.dbt.drop_relation_if_exists": {"name": "drop_relation_if_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop.sql", "original_file_path": "macros/relations/drop.sql", "unique_id": "macro.dbt.drop_relation_if_exists", "macro_sql": "{% macro drop_relation_if_exists(relation) %}\n  {% if relation is not none %}\n    {{ adapter.drop_relation(relation) }}\n  {% endif %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.355237, "supported_languages": null}, "macro.dbt.get_replace_sql": {"name": "get_replace_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/replace.sql", "original_file_path": "macros/relations/replace.sql", "unique_id": "macro.dbt.get_replace_sql", "macro_sql": "{% macro get_replace_sql(existing_relation, target_relation, sql) %}\n    {{- log('Applying REPLACE to: ' ~ existing_relation) -}}\n    {{- adapter.dispatch('get_replace_sql', 'dbt')(existing_relation, target_relation, sql) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_replace_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.355992, "supported_languages": null}, "macro.dbt.default__get_replace_sql": {"name": "default__get_replace_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/replace.sql", "original_file_path": "macros/relations/replace.sql", "unique_id": "macro.dbt.default__get_replace_sql", "macro_sql": "{% macro default__get_replace_sql(existing_relation, target_relation, sql) %}\n\n    {# /* use a create or replace statement if possible */ #}\n\n    {% set is_replaceable = existing_relation.type == target_relation_type and existing_relation.can_be_replaced %}\n\n    {% if is_replaceable and existing_relation.is_view %}\n        {{ get_replace_view_sql(target_relation, sql) }}\n\n    {% elif is_replaceable and existing_relation.is_table %}\n        {{ get_replace_table_sql(target_relation, sql) }}\n\n    {% elif is_replaceable and existing_relation.is_materialized_view %}\n        {{ get_replace_materialized_view_sql(target_relation, sql) }}\n\n    {# /* a create or replace statement is not possible, so try to stage and/or backup to be safe */ #}\n\n    {# /* create target_relation as an intermediate relation, then swap it out with the existing one using a backup */ #}\n    {%- elif target_relation.can_be_renamed and existing_relation.can_be_renamed -%}\n        {{ get_create_intermediate_sql(target_relation, sql) }};\n        {{ get_create_backup_sql(existing_relation) }};\n        {{ get_rename_intermediate_sql(target_relation) }};\n        {{ get_drop_backup_sql(existing_relation) }}\n\n    {# /* create target_relation as an intermediate relation, then swap it out with the existing one without using a backup */ #}\n    {%- elif target_relation.can_be_renamed -%}\n        {{ get_create_intermediate_sql(target_relation, sql) }};\n        {{ get_drop_sql(existing_relation) }};\n        {{ get_rename_intermediate_sql(target_relation) }}\n\n    {# /* create target_relation in place by first backing up the existing relation */ #}\n    {%- elif existing_relation.can_be_renamed -%}\n        {{ get_create_backup_sql(existing_relation) }};\n        {{ get_create_sql(target_relation, sql) }};\n        {{ get_drop_backup_sql(existing_relation) }}\n\n    {# /* no renaming is allowed, so just drop and create */ #}\n    {%- else -%}\n        {{ get_drop_sql(existing_relation) }};\n        {{ get_create_sql(target_relation, sql) }}\n\n    {%- endif -%}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_replace_view_sql", "macro.dbt.get_replace_table_sql", "macro.dbt.get_replace_materialized_view_sql", "macro.dbt.get_create_intermediate_sql", "macro.dbt.get_create_backup_sql", "macro.dbt.get_rename_intermediate_sql", "macro.dbt.get_drop_backup_sql", "macro.dbt.get_drop_sql", "macro.dbt.get_create_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3573382, "supported_languages": null}, "macro.dbt.get_create_intermediate_sql": {"name": "get_create_intermediate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create_intermediate.sql", "original_file_path": "macros/relations/create_intermediate.sql", "unique_id": "macro.dbt.get_create_intermediate_sql", "macro_sql": "{%- macro get_create_intermediate_sql(relation, sql) -%}\n    {{- log('Applying CREATE INTERMEDIATE to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_create_intermediate_sql', 'dbt')(relation, sql) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_create_intermediate_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.357704, "supported_languages": null}, "macro.dbt.default__get_create_intermediate_sql": {"name": "default__get_create_intermediate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create_intermediate.sql", "original_file_path": "macros/relations/create_intermediate.sql", "unique_id": "macro.dbt.default__get_create_intermediate_sql", "macro_sql": "{%- macro default__get_create_intermediate_sql(relation, sql) -%}\n\n    -- get the standard intermediate name\n    {% set intermediate_relation = make_intermediate_relation(relation) %}\n\n    -- drop any pre-existing intermediate\n    {{ get_drop_sql(intermediate_relation) }};\n\n    {{ get_create_sql(intermediate_relation, sql) }}\n\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt.make_intermediate_relation", "macro.dbt.get_drop_sql", "macro.dbt.get_create_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3579578, "supported_languages": null}, "macro.dbt.get_drop_backup_sql": {"name": "get_drop_backup_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop_backup.sql", "original_file_path": "macros/relations/drop_backup.sql", "unique_id": "macro.dbt.get_drop_backup_sql", "macro_sql": "{%- macro get_drop_backup_sql(relation) -%}\n    {{- log('Applying DROP BACKUP to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_drop_backup_sql', 'dbt')(relation) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_drop_backup_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.35826, "supported_languages": null}, "macro.dbt.default__get_drop_backup_sql": {"name": "default__get_drop_backup_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/drop_backup.sql", "original_file_path": "macros/relations/drop_backup.sql", "unique_id": "macro.dbt.default__get_drop_backup_sql", "macro_sql": "{%- macro default__get_drop_backup_sql(relation) -%}\n\n    -- get the standard backup name\n    {% set backup_relation = make_backup_relation(relation, relation.type) %}\n\n    {{ get_drop_sql(backup_relation) }}\n\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt.make_backup_relation", "macro.dbt.get_drop_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.358452, "supported_languages": null}, "macro.dbt.get_rename_sql": {"name": "get_rename_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename.sql", "original_file_path": "macros/relations/rename.sql", "unique_id": "macro.dbt.get_rename_sql", "macro_sql": "{%- macro get_rename_sql(relation, new_name) -%}\n    {{- log('Applying RENAME to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_rename_sql', 'dbt')(relation, new_name) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_rename_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.359222, "supported_languages": null}, "macro.dbt.default__get_rename_sql": {"name": "default__get_rename_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename.sql", "original_file_path": "macros/relations/rename.sql", "unique_id": "macro.dbt.default__get_rename_sql", "macro_sql": "{%- macro default__get_rename_sql(relation, new_name) -%}\n\n    {%- if relation.is_view -%}\n        {{ get_rename_view_sql(relation, new_name) }}\n\n    {%- elif relation.is_table -%}\n        {{ get_rename_table_sql(relation, new_name) }}\n\n    {%- elif relation.is_materialized_view -%}\n        {{ get_rename_materialized_view_sql(relation, new_name) }}\n\n    {%- else -%}\n        {{- exceptions.raise_compiler_error(\"`get_rename_sql` has not been implemented for: \" ~ relation.type ) -}}\n\n    {%- endif -%}\n\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.get_rename_view_sql", "macro.dbt.get_rename_table_sql", "macro.dbt.get_rename_materialized_view_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.359672, "supported_languages": null}, "macro.dbt.rename_relation": {"name": "rename_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename.sql", "original_file_path": "macros/relations/rename.sql", "unique_id": "macro.dbt.rename_relation", "macro_sql": "{% macro rename_relation(from_relation, to_relation) -%}\n  {{ return(adapter.dispatch('rename_relation', 'dbt')(from_relation, to_relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__rename_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.359879, "supported_languages": null}, "macro.dbt.default__rename_relation": {"name": "default__rename_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename.sql", "original_file_path": "macros/relations/rename.sql", "unique_id": "macro.dbt.default__rename_relation", "macro_sql": "{% macro default__rename_relation(from_relation, to_relation) -%}\n  {% set target_name = adapter.quote_as_configured(to_relation.identifier, 'identifier') %}\n  {% call statement('rename_relation') -%}\n    alter table {{ from_relation }} rename to {{ target_name }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.360169, "supported_languages": null}, "macro.dbt.get_create_backup_sql": {"name": "get_create_backup_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create_backup.sql", "original_file_path": "macros/relations/create_backup.sql", "unique_id": "macro.dbt.get_create_backup_sql", "macro_sql": "{%- macro get_create_backup_sql(relation) -%}\n    {{- log('Applying CREATE BACKUP to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_create_backup_sql', 'dbt')(relation) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_create_backup_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.360509, "supported_languages": null}, "macro.dbt.default__get_create_backup_sql": {"name": "default__get_create_backup_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create_backup.sql", "original_file_path": "macros/relations/create_backup.sql", "unique_id": "macro.dbt.default__get_create_backup_sql", "macro_sql": "{%- macro default__get_create_backup_sql(relation) -%}\n\n    -- get the standard backup name\n    {% set backup_relation = make_backup_relation(relation, relation.type) %}\n\n    -- drop any pre-existing backup\n    {{ get_drop_sql(backup_relation) }};\n\n    {{ get_rename_sql(relation, backup_relation.identifier) }}\n\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt.make_backup_relation", "macro.dbt.get_drop_sql", "macro.dbt.get_rename_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.360769, "supported_languages": null}, "macro.dbt.get_create_sql": {"name": "get_create_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create.sql", "original_file_path": "macros/relations/create.sql", "unique_id": "macro.dbt.get_create_sql", "macro_sql": "{%- macro get_create_sql(relation, sql) -%}\n    {{- log('Applying CREATE to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_create_sql', 'dbt')(relation, sql) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_create_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.361225, "supported_languages": null}, "macro.dbt.default__get_create_sql": {"name": "default__get_create_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/create.sql", "original_file_path": "macros/relations/create.sql", "unique_id": "macro.dbt.default__get_create_sql", "macro_sql": "{%- macro default__get_create_sql(relation, sql) -%}\n\n    {%- if relation.is_view -%}\n        {{ get_create_view_as_sql(relation, sql) }}\n\n    {%- elif relation.is_table -%}\n        {{ get_create_table_as_sql(False, relation, sql) }}\n\n    {%- elif relation.is_materialized_view -%}\n        {{ get_create_materialized_view_as_sql(relation, sql) }}\n\n    {%- else -%}\n        {{- exceptions.raise_compiler_error(\"`get_create_sql` has not been implemented for: \" ~ relation.type ) -}}\n\n    {%- endif -%}\n\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt.get_create_view_as_sql", "macro.dbt.get_create_table_as_sql", "macro.dbt.get_create_materialized_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3616471, "supported_languages": null}, "macro.dbt.get_rename_intermediate_sql": {"name": "get_rename_intermediate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename_intermediate.sql", "original_file_path": "macros/relations/rename_intermediate.sql", "unique_id": "macro.dbt.get_rename_intermediate_sql", "macro_sql": "{%- macro get_rename_intermediate_sql(relation) -%}\n    {{- log('Applying RENAME INTERMEDIATE to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_rename_intermediate_sql', 'dbt')(relation) -}}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": ["macro.dbt.default__get_rename_intermediate_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3619862, "supported_languages": null}, "macro.dbt.default__get_rename_intermediate_sql": {"name": "default__get_rename_intermediate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/rename_intermediate.sql", "original_file_path": "macros/relations/rename_intermediate.sql", "unique_id": "macro.dbt.default__get_rename_intermediate_sql", "macro_sql": "{%- macro default__get_rename_intermediate_sql(relation) -%}\n\n    -- get the standard intermediate name\n    {% set intermediate_relation = make_intermediate_relation(relation) %}\n\n    {{ get_rename_sql(intermediate_relation, relation.identifier) }}\n\n{%- endmacro -%}", "depends_on": {"macros": ["macro.dbt.make_intermediate_relation", "macro.dbt.get_rename_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3621829, "supported_languages": null}, "macro.dbt.drop_materialized_view": {"name": "drop_materialized_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/drop.sql", "original_file_path": "macros/relations/materialized_view/drop.sql", "unique_id": "macro.dbt.drop_materialized_view", "macro_sql": "{% macro drop_materialized_view(relation) -%}\n    {{ return(adapter.dispatch('drop_materialized_view', 'dbt')(relation)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__drop_materialized_view"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.362443, "supported_languages": null}, "macro.dbt.default__drop_materialized_view": {"name": "default__drop_materialized_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/drop.sql", "original_file_path": "macros/relations/materialized_view/drop.sql", "unique_id": "macro.dbt.default__drop_materialized_view", "macro_sql": "{% macro default__drop_materialized_view(relation) -%}\n    drop materialized view if exists {{ relation }} cascade\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.36256, "supported_languages": null}, "macro.dbt.get_replace_materialized_view_sql": {"name": "get_replace_materialized_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/replace.sql", "original_file_path": "macros/relations/materialized_view/replace.sql", "unique_id": "macro.dbt.get_replace_materialized_view_sql", "macro_sql": "{% macro get_replace_materialized_view_sql(relation, sql) %}\n    {{- adapter.dispatch('get_replace_materialized_view_sql', 'dbt')(relation, sql) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_replace_materialized_view_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.362815, "supported_languages": null}, "macro.dbt.default__get_replace_materialized_view_sql": {"name": "default__get_replace_materialized_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/replace.sql", "original_file_path": "macros/relations/materialized_view/replace.sql", "unique_id": "macro.dbt.default__get_replace_materialized_view_sql", "macro_sql": "{% macro default__get_replace_materialized_view_sql(relation, sql) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_replace_materialized_view_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.362957, "supported_languages": null}, "macro.dbt.refresh_materialized_view": {"name": "refresh_materialized_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/refresh.sql", "original_file_path": "macros/relations/materialized_view/refresh.sql", "unique_id": "macro.dbt.refresh_materialized_view", "macro_sql": "{% macro refresh_materialized_view(relation) %}\n    {{- log('Applying REFRESH to: ' ~ relation) -}}\n    {{- adapter.dispatch('refresh_materialized_view', 'dbt')(relation) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__refresh_materialized_view"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.363263, "supported_languages": null}, "macro.dbt.default__refresh_materialized_view": {"name": "default__refresh_materialized_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/refresh.sql", "original_file_path": "macros/relations/materialized_view/refresh.sql", "unique_id": "macro.dbt.default__refresh_materialized_view", "macro_sql": "{% macro default__refresh_materialized_view(relation) %}\n    {{ exceptions.raise_compiler_error(\"`refresh_materialized_view` has not been implemented for this adapter.\") }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.363452, "supported_languages": null}, "macro.dbt.get_rename_materialized_view_sql": {"name": "get_rename_materialized_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/rename.sql", "original_file_path": "macros/relations/materialized_view/rename.sql", "unique_id": "macro.dbt.get_rename_materialized_view_sql", "macro_sql": "{% macro get_rename_materialized_view_sql(relation, new_name) %}\n    {{- adapter.dispatch('get_rename_materialized_view_sql', 'dbt')(relation, new_name) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_rename_materialized_view_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.363706, "supported_languages": null}, "macro.dbt.default__get_rename_materialized_view_sql": {"name": "default__get_rename_materialized_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/rename.sql", "original_file_path": "macros/relations/materialized_view/rename.sql", "unique_id": "macro.dbt.default__get_rename_materialized_view_sql", "macro_sql": "{% macro default__get_rename_materialized_view_sql(relation, new_name) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_rename_materialized_view_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.363841, "supported_languages": null}, "macro.dbt.get_alter_materialized_view_as_sql": {"name": "get_alter_materialized_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/alter.sql", "original_file_path": "macros/relations/materialized_view/alter.sql", "unique_id": "macro.dbt.get_alter_materialized_view_as_sql", "macro_sql": "{% macro get_alter_materialized_view_as_sql(\n    relation,\n    configuration_changes,\n    sql,\n    existing_relation,\n    backup_relation,\n    intermediate_relation\n) %}\n    {{- log('Applying ALTER to: ' ~ relation) -}}\n    {{- adapter.dispatch('get_alter_materialized_view_as_sql', 'dbt')(\n        relation,\n        configuration_changes,\n        sql,\n        existing_relation,\n        backup_relation,\n        intermediate_relation\n    ) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_alter_materialized_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.364435, "supported_languages": null}, "macro.dbt.default__get_alter_materialized_view_as_sql": {"name": "default__get_alter_materialized_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/alter.sql", "original_file_path": "macros/relations/materialized_view/alter.sql", "unique_id": "macro.dbt.default__get_alter_materialized_view_as_sql", "macro_sql": "{% macro default__get_alter_materialized_view_as_sql(\n    relation,\n    configuration_changes,\n    sql,\n    existing_relation,\n    backup_relation,\n    intermediate_relation\n) %}\n    {{ exceptions.raise_compiler_error(\"Materialized views have not been implemented for this adapter.\") }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.36461, "supported_languages": null}, "macro.dbt.get_materialized_view_configuration_changes": {"name": "get_materialized_view_configuration_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/alter.sql", "original_file_path": "macros/relations/materialized_view/alter.sql", "unique_id": "macro.dbt.get_materialized_view_configuration_changes", "macro_sql": "{% macro get_materialized_view_configuration_changes(existing_relation, new_config) %}\n    /* {#\n    It's recommended that configuration changes be formatted as follows:\n    {\"<change_category>\": [{\"action\": \"<name>\", \"context\": ...}]}\n\n    For example:\n    {\n        \"indexes\": [\n            {\"action\": \"drop\", \"context\": \"index_abc\"},\n            {\"action\": \"create\", \"context\": {\"columns\": [\"column_1\", \"column_2\"], \"type\": \"hash\", \"unique\": True}},\n        ],\n    }\n\n    Either way, `get_materialized_view_configuration_changes` needs to align with `get_alter_materialized_view_as_sql`.\n    #} */\n    {{- log('Determining configuration changes on: ' ~ existing_relation) -}}\n    {%- do return(adapter.dispatch('get_materialized_view_configuration_changes', 'dbt')(existing_relation, new_config)) -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_materialized_view_configuration_changes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3648782, "supported_languages": null}, "macro.dbt.default__get_materialized_view_configuration_changes": {"name": "default__get_materialized_view_configuration_changes", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/alter.sql", "original_file_path": "macros/relations/materialized_view/alter.sql", "unique_id": "macro.dbt.default__get_materialized_view_configuration_changes", "macro_sql": "{% macro default__get_materialized_view_configuration_changes(existing_relation, new_config) %}\n    {{ exceptions.raise_compiler_error(\"Materialized views have not been implemented for this adapter.\") }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.365012, "supported_languages": null}, "macro.dbt.get_create_materialized_view_as_sql": {"name": "get_create_materialized_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/create.sql", "original_file_path": "macros/relations/materialized_view/create.sql", "unique_id": "macro.dbt.get_create_materialized_view_as_sql", "macro_sql": "{% macro get_create_materialized_view_as_sql(relation, sql) -%}\n    {{- adapter.dispatch('get_create_materialized_view_as_sql', 'dbt')(relation, sql) -}}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_materialized_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.365271, "supported_languages": null}, "macro.dbt.default__get_create_materialized_view_as_sql": {"name": "default__get_create_materialized_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/materialized_view/create.sql", "original_file_path": "macros/relations/materialized_view/create.sql", "unique_id": "macro.dbt.default__get_create_materialized_view_as_sql", "macro_sql": "{% macro default__get_create_materialized_view_as_sql(relation, sql) -%}\n    {{ exceptions.raise_compiler_error(\n        \"`get_create_materialized_view_as_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.365404, "supported_languages": null}, "macro.dbt.get_table_columns_and_constraints": {"name": "get_table_columns_and_constraints", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.get_table_columns_and_constraints", "macro_sql": "{%- macro get_table_columns_and_constraints() -%}\n  {{ adapter.dispatch('get_table_columns_and_constraints', 'dbt')() }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__get_table_columns_and_constraints"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3663511, "supported_languages": null}, "macro.dbt.default__get_table_columns_and_constraints": {"name": "default__get_table_columns_and_constraints", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.default__get_table_columns_and_constraints", "macro_sql": "{% macro default__get_table_columns_and_constraints() -%}\n  {{ return(table_columns_and_constraints()) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.table_columns_and_constraints"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.366464, "supported_languages": null}, "macro.dbt.table_columns_and_constraints": {"name": "table_columns_and_constraints", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.table_columns_and_constraints", "macro_sql": "{% macro table_columns_and_constraints() %}\n  {# loop through user_provided_columns to create DDL with data types and constraints #}\n    {%- set raw_column_constraints = adapter.render_raw_columns_constraints(raw_columns=model['columns']) -%}\n    {%- set raw_model_constraints = adapter.render_raw_model_constraints(raw_constraints=model['constraints']) -%}\n    (\n    {% for c in raw_column_constraints -%}\n      {{ c }}{{ \",\" if not loop.last or raw_model_constraints }}\n    {% endfor %}\n    {% for c in raw_model_constraints -%}\n        {{ c }}{{ \",\" if not loop.last }}\n    {% endfor -%}\n    )\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.366965, "supported_languages": null}, "macro.dbt.get_assert_columns_equivalent": {"name": "get_assert_columns_equivalent", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.get_assert_columns_equivalent", "macro_sql": "\n\n{%- macro get_assert_columns_equivalent(sql) -%}\n  {{ adapter.dispatch('get_assert_columns_equivalent', 'dbt')(sql) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__get_assert_columns_equivalent"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.367124, "supported_languages": null}, "macro.dbt.default__get_assert_columns_equivalent": {"name": "default__get_assert_columns_equivalent", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.default__get_assert_columns_equivalent", "macro_sql": "{% macro default__get_assert_columns_equivalent(sql) -%}\n  {{ return(assert_columns_equivalent(sql)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.assert_columns_equivalent"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.367249, "supported_languages": null}, "macro.dbt.assert_columns_equivalent": {"name": "assert_columns_equivalent", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.assert_columns_equivalent", "macro_sql": "{% macro assert_columns_equivalent(sql) %}\n\n  {#-- First ensure the user has defined 'columns' in yaml specification --#}\n  {%- set user_defined_columns = model['columns'] -%}\n  {%- if not user_defined_columns -%}\n      {{ exceptions.raise_contract_error([], []) }}\n  {%- endif -%}\n\n  {#-- Obtain the column schema provided by sql file. #}\n  {%- set sql_file_provided_columns = get_column_schema_from_query(sql, config.get('sql_header', none)) -%}\n  {#--Obtain the column schema provided by the schema file by generating an 'empty schema' query from the model's columns. #}\n  {%- set schema_file_provided_columns = get_column_schema_from_query(get_empty_schema_sql(user_defined_columns)) -%}\n\n  {#-- create dictionaries with name and formatted data type and strings for exception #}\n  {%- set sql_columns = format_columns(sql_file_provided_columns) -%}\n  {%- set yaml_columns = format_columns(schema_file_provided_columns)  -%}\n\n  {%- if sql_columns|length != yaml_columns|length -%}\n    {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}\n  {%- endif -%}\n\n  {%- for sql_col in sql_columns -%}\n    {%- set yaml_col = [] -%}\n    {%- for this_col in yaml_columns -%}\n      {%- if this_col['name'] == sql_col['name'] -%}\n        {%- do yaml_col.append(this_col) -%}\n        {%- break -%}\n      {%- endif -%}\n    {%- endfor -%}\n    {%- if not yaml_col -%}\n      {#-- Column with name not found in yaml #}\n      {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}\n    {%- endif -%}\n    {%- if sql_col['formatted'] != yaml_col[0]['formatted'] -%}\n      {#-- Column data types don't match #}\n      {%- do exceptions.raise_contract_error(yaml_columns, sql_columns) -%}\n    {%- endif -%}\n  {%- endfor -%}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_column_schema_from_query", "macro.dbt.get_empty_schema_sql", "macro.dbt.format_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.368504, "supported_languages": null}, "macro.dbt.format_columns": {"name": "format_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.format_columns", "macro_sql": "{% macro format_columns(columns) %}\n  {% set formatted_columns = [] %}\n  {% for column in columns %}\n    {%- set formatted_column = adapter.dispatch('format_column', 'dbt')(column) -%}\n    {%- do formatted_columns.append(formatted_column) -%}\n  {% endfor %}\n  {{ return(formatted_columns) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__format_column"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.368866, "supported_languages": null}, "macro.dbt.default__format_column": {"name": "default__format_column", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/column/columns_spec_ddl.sql", "original_file_path": "macros/relations/column/columns_spec_ddl.sql", "unique_id": "macro.dbt.default__format_column", "macro_sql": "{% macro default__format_column(column) -%}\n  {% set data_type = column.dtype %}\n  {% set formatted = column.column.lower() ~ \" \" ~ data_type %}\n  {{ return({'name': column.name, 'data_type': data_type, 'formatted': formatted}) }}\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.369202, "supported_languages": null}, "macro.dbt.drop_table": {"name": "drop_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/drop.sql", "original_file_path": "macros/relations/table/drop.sql", "unique_id": "macro.dbt.drop_table", "macro_sql": "{% macro drop_table(relation) -%}\n    {{ return(adapter.dispatch('drop_table', 'dbt')(relation)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__drop_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3694642, "supported_languages": null}, "macro.dbt.default__drop_table": {"name": "default__drop_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/drop.sql", "original_file_path": "macros/relations/table/drop.sql", "unique_id": "macro.dbt.default__drop_table", "macro_sql": "{% macro default__drop_table(relation) -%}\n    drop table if exists {{ relation }} cascade\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3695629, "supported_languages": null}, "macro.dbt.get_replace_table_sql": {"name": "get_replace_table_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/replace.sql", "original_file_path": "macros/relations/table/replace.sql", "unique_id": "macro.dbt.get_replace_table_sql", "macro_sql": "{% macro get_replace_table_sql(relation, sql) %}\n    {{- adapter.dispatch('get_replace_table_sql', 'dbt')(relation, sql) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_replace_table_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.369812, "supported_languages": null}, "macro.dbt.default__get_replace_table_sql": {"name": "default__get_replace_table_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/replace.sql", "original_file_path": "macros/relations/table/replace.sql", "unique_id": "macro.dbt.default__get_replace_table_sql", "macro_sql": "{% macro default__get_replace_table_sql(relation, sql) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_replace_table_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.369948, "supported_languages": null}, "macro.dbt.get_rename_table_sql": {"name": "get_rename_table_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/rename.sql", "original_file_path": "macros/relations/table/rename.sql", "unique_id": "macro.dbt.get_rename_table_sql", "macro_sql": "{% macro get_rename_table_sql(relation, new_name) %}\n    {{- adapter.dispatch('get_rename_table_sql', 'dbt')(relation, new_name) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_rename_table_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.370205, "supported_languages": null}, "macro.dbt.default__get_rename_table_sql": {"name": "default__get_rename_table_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/rename.sql", "original_file_path": "macros/relations/table/rename.sql", "unique_id": "macro.dbt.default__get_rename_table_sql", "macro_sql": "{% macro default__get_rename_table_sql(relation, new_name) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_rename_table_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.370343, "supported_languages": null}, "macro.dbt.get_create_table_as_sql": {"name": "get_create_table_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.get_create_table_as_sql", "macro_sql": "{% macro get_create_table_as_sql(temporary, relation, sql) -%}\n  {{ adapter.dispatch('get_create_table_as_sql', 'dbt')(temporary, relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_table_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.371142, "supported_languages": null}, "macro.dbt.default__get_create_table_as_sql": {"name": "default__get_create_table_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.default__get_create_table_as_sql", "macro_sql": "{% macro default__get_create_table_as_sql(temporary, relation, sql) -%}\n  {{ return(create_table_as(temporary, relation, sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.371315, "supported_languages": null}, "macro.dbt.create_table_as": {"name": "create_table_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.create_table_as", "macro_sql": "{% macro create_table_as(temporary, relation, compiled_code, language='sql') -%}\n  {# backward compatibility for create_table_as that does not support language #}\n  {% if language == \"sql\" %}\n    {{ adapter.dispatch('create_table_as', 'dbt')(temporary, relation, compiled_code)}}\n  {% else %}\n    {{ adapter.dispatch('create_table_as', 'dbt')(temporary, relation, compiled_code, language) }}\n  {% endif %}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_table_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.371722, "supported_languages": null}, "macro.dbt.default__create_table_as": {"name": "default__create_table_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.default__create_table_as", "macro_sql": "{% macro default__create_table_as(temporary, relation, sql) -%}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n\n  create {% if temporary: -%}temporary{%- endif %} table\n    {{ relation.include(database=(not temporary), schema=(not temporary)) }}\n  {% set contract_config = config.get('contract') %}\n  {% if contract_config.enforced and (not temporary) %}\n    {{ get_assert_columns_equivalent(sql) }}\n    {{ get_table_columns_and_constraints() }}\n    {%- set sql = get_select_subquery(sql) %}\n  {% endif %}\n  as (\n    {{ sql }}\n  );\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_assert_columns_equivalent", "macro.dbt.get_table_columns_and_constraints", "macro.dbt.get_select_subquery"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3723981, "supported_languages": null}, "macro.dbt.default__get_column_names": {"name": "default__get_column_names", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.default__get_column_names", "macro_sql": "{% macro default__get_column_names() %}\n  {#- loop through user_provided_columns to get column names -#}\n    {%- set user_provided_columns = model['columns'] -%}\n    {%- for i in user_provided_columns %}\n      {%- set col = user_provided_columns[i] -%}\n      {%- set col_name = adapter.quote(col['name']) if col.get('quote') else col['name'] -%}\n      {{ col_name }}{{ \", \" if not loop.last }}\n    {%- endfor -%}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.372839, "supported_languages": null}, "macro.dbt.get_select_subquery": {"name": "get_select_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.get_select_subquery", "macro_sql": "{% macro get_select_subquery(sql) %}\n  {{ return(adapter.dispatch('get_select_subquery', 'dbt')(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_select_subquery"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3730109, "supported_languages": null}, "macro.dbt.default__get_select_subquery": {"name": "default__get_select_subquery", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/table/create.sql", "original_file_path": "macros/relations/table/create.sql", "unique_id": "macro.dbt.default__get_select_subquery", "macro_sql": "{% macro default__get_select_subquery(sql) %}\n    select {{ adapter.dispatch('get_column_names', 'dbt')() }}\n    from (\n        {{ sql }}\n    ) as model_subq\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.get_column_names", "macro.dbt.default__get_column_names"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.373178, "supported_languages": null}, "macro.dbt.drop_view": {"name": "drop_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/drop.sql", "original_file_path": "macros/relations/view/drop.sql", "unique_id": "macro.dbt.drop_view", "macro_sql": "{% macro drop_view(relation) -%}\n    {{ return(adapter.dispatch('drop_view', 'dbt')(relation)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__drop_view"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.373425, "supported_languages": null}, "macro.dbt.default__drop_view": {"name": "default__drop_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/drop.sql", "original_file_path": "macros/relations/view/drop.sql", "unique_id": "macro.dbt.default__drop_view", "macro_sql": "{% macro default__drop_view(relation) -%}\n    drop view if exists {{ relation }} cascade\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3735301, "supported_languages": null}, "macro.dbt.get_replace_view_sql": {"name": "get_replace_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/replace.sql", "original_file_path": "macros/relations/view/replace.sql", "unique_id": "macro.dbt.get_replace_view_sql", "macro_sql": "{% macro get_replace_view_sql(relation, sql) %}\n    {{- adapter.dispatch('get_replace_view_sql', 'dbt')(relation, sql) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_replace_view_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.374401, "supported_languages": null}, "macro.dbt.default__get_replace_view_sql": {"name": "default__get_replace_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/replace.sql", "original_file_path": "macros/relations/view/replace.sql", "unique_id": "macro.dbt.default__get_replace_view_sql", "macro_sql": "{% macro default__get_replace_view_sql(relation, sql) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_replace_view_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.374536, "supported_languages": null}, "macro.dbt.create_or_replace_view": {"name": "create_or_replace_view", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/replace.sql", "original_file_path": "macros/relations/view/replace.sql", "unique_id": "macro.dbt.create_or_replace_view", "macro_sql": "{% macro create_or_replace_view() %}\n  {%- set identifier = model['alias'] -%}\n\n  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}\n  {%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}\n\n  {%- set target_relation = api.Relation.create(\n      identifier=identifier, schema=schema, database=database,\n      type='view') -%}\n  {% set grant_config = config.get('grants') %}\n\n  {{ run_hooks(pre_hooks) }}\n\n  -- If there's a table with the same name and we weren't told to full refresh,\n  -- that's an error. If we were told to full refresh, drop it. This behavior differs\n  -- for Snowflake and BigQuery, so multiple dispatch is used.\n  {%- if old_relation is not none and old_relation.is_table -%}\n    {{ handle_existing_table(should_full_refresh(), old_relation) }}\n  {%- endif -%}\n\n  -- build model\n  {% call statement('main') -%}\n    {{ get_create_view_as_sql(target_relation, sql) }}\n  {%- endcall %}\n\n  {% set should_revoke = should_revoke(exists_as_view, full_refresh_mode=True) %}\n  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}\n\n  {{ run_hooks(post_hooks) }}\n\n  {{ return({'relations': [target_relation]}) }}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_hooks", "macro.dbt.handle_existing_table", "macro.dbt.should_full_refresh", "macro.dbt.statement", "macro.dbt.get_create_view_as_sql", "macro.dbt.should_revoke", "macro.dbt.apply_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.37571, "supported_languages": null}, "macro.dbt.handle_existing_table": {"name": "handle_existing_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/replace.sql", "original_file_path": "macros/relations/view/replace.sql", "unique_id": "macro.dbt.handle_existing_table", "macro_sql": "{% macro handle_existing_table(full_refresh, old_relation) %}\n    {{ adapter.dispatch('handle_existing_table', 'dbt')(full_refresh, old_relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__handle_existing_table"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.375901, "supported_languages": null}, "macro.dbt.default__handle_existing_table": {"name": "default__handle_existing_table", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/replace.sql", "original_file_path": "macros/relations/view/replace.sql", "unique_id": "macro.dbt.default__handle_existing_table", "macro_sql": "{% macro default__handle_existing_table(full_refresh, old_relation) %}\n    {{ log(\"Dropping relation \" ~ old_relation ~ \" because it is of type \" ~ old_relation.type) }}\n    {{ adapter.drop_relation(old_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3761091, "supported_languages": null}, "macro.dbt.get_rename_view_sql": {"name": "get_rename_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/rename.sql", "original_file_path": "macros/relations/view/rename.sql", "unique_id": "macro.dbt.get_rename_view_sql", "macro_sql": "{% macro get_rename_view_sql(relation, new_name) %}\n    {{- adapter.dispatch('get_rename_view_sql', 'dbt')(relation, new_name) -}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_rename_view_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3763762, "supported_languages": null}, "macro.dbt.default__get_rename_view_sql": {"name": "default__get_rename_view_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/rename.sql", "original_file_path": "macros/relations/view/rename.sql", "unique_id": "macro.dbt.default__get_rename_view_sql", "macro_sql": "{% macro default__get_rename_view_sql(relation, new_name) %}\n    {{ exceptions.raise_compiler_error(\n        \"`get_rename_view_sql` has not been implemented for this adapter.\"\n    ) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3765209, "supported_languages": null}, "macro.dbt.get_create_view_as_sql": {"name": "get_create_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/create.sql", "original_file_path": "macros/relations/view/create.sql", "unique_id": "macro.dbt.get_create_view_as_sql", "macro_sql": "{% macro get_create_view_as_sql(relation, sql) -%}\n  {{ adapter.dispatch('get_create_view_as_sql', 'dbt')(relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_view_as_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.376925, "supported_languages": null}, "macro.dbt.default__get_create_view_as_sql": {"name": "default__get_create_view_as_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/create.sql", "original_file_path": "macros/relations/view/create.sql", "unique_id": "macro.dbt.default__get_create_view_as_sql", "macro_sql": "{% macro default__get_create_view_as_sql(relation, sql) -%}\n  {{ return(create_view_as(relation, sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.create_view_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.377078, "supported_languages": null}, "macro.dbt.create_view_as": {"name": "create_view_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/create.sql", "original_file_path": "macros/relations/view/create.sql", "unique_id": "macro.dbt.create_view_as", "macro_sql": "{% macro create_view_as(relation, sql) -%}\n  {{ adapter.dispatch('create_view_as', 'dbt')(relation, sql) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_view_as"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.37725, "supported_languages": null}, "macro.dbt.default__create_view_as": {"name": "default__create_view_as", "resource_type": "macro", "package_name": "dbt", "path": "macros/relations/view/create.sql", "original_file_path": "macros/relations/view/create.sql", "unique_id": "macro.dbt.default__create_view_as", "macro_sql": "{% macro default__create_view_as(relation, sql) -%}\n  {%- set sql_header = config.get('sql_header', none) -%}\n\n  {{ sql_header if sql_header is not none }}\n  create view {{ relation }}\n    {% set contract_config = config.get('contract') %}\n    {% if contract_config.enforced %}\n      {{ get_assert_columns_equivalent(sql) }}\n    {%- endif %}\n  as (\n    {{ sql }}\n  );\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.get_assert_columns_equivalent"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.377648, "supported_languages": null}, "macro.dbt.default__test_relationships": {"name": "default__test_relationships", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/relationships.sql", "original_file_path": "macros/generic_test_sql/relationships.sql", "unique_id": "macro.dbt.default__test_relationships", "macro_sql": "{% macro default__test_relationships(model, column_name, to, field) %}\n\nwith child as (\n    select {{ column_name }} as from_field\n    from {{ model }}\n    where {{ column_name }} is not null\n),\n\nparent as (\n    select {{ field }} as to_field\n    from {{ to }}\n)\n\nselect\n    from_field\n\nfrom child\nleft join parent\n    on child.from_field = parent.to_field\n\nwhere parent.to_field is null\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.378002, "supported_languages": null}, "macro.dbt.default__test_not_null": {"name": "default__test_not_null", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/not_null.sql", "original_file_path": "macros/generic_test_sql/not_null.sql", "unique_id": "macro.dbt.default__test_not_null", "macro_sql": "{% macro default__test_not_null(model, column_name) %}\n\n{% set column_list = '*' if should_store_failures() else column_name %}\n\nselect {{ column_list }}\nfrom {{ model }}\nwhere {{ column_name }} is null\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.should_store_failures"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.378277, "supported_languages": null}, "macro.dbt.default__test_unique": {"name": "default__test_unique", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/unique.sql", "original_file_path": "macros/generic_test_sql/unique.sql", "unique_id": "macro.dbt.default__test_unique", "macro_sql": "{% macro default__test_unique(model, column_name) %}\n\nselect\n    {{ column_name }} as unique_field,\n    count(*) as n_records\n\nfrom {{ model }}\nwhere {{ column_name }} is not null\ngroup by {{ column_name }}\nhaving count(*) > 1\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.378516, "supported_languages": null}, "macro.dbt.default__test_accepted_values": {"name": "default__test_accepted_values", "resource_type": "macro", "package_name": "dbt", "path": "macros/generic_test_sql/accepted_values.sql", "original_file_path": "macros/generic_test_sql/accepted_values.sql", "unique_id": "macro.dbt.default__test_accepted_values", "macro_sql": "{% macro default__test_accepted_values(model, column_name, values, quote=True) %}\n\nwith all_values as (\n\n    select\n        {{ column_name }} as value_field,\n        count(*) as n_records\n\n    from {{ model }}\n    group by {{ column_name }}\n\n)\n\nselect *\nfrom all_values\nwhere value_field not in (\n    {% for value in values -%}\n        {% if quote -%}\n        '{{ value }}'\n        {%- else -%}\n        {{ value }}\n        {%- endif -%}\n        {%- if not loop.last -%},{%- endif %}\n    {%- endfor %}\n)\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3790772, "supported_languages": null}, "macro.dbt.statement": {"name": "statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.statement", "macro_sql": "\n{%- macro statement(name=None, fetch_result=False, auto_begin=True, language='sql') -%}\n  {%- if execute: -%}\n    {%- set compiled_code = caller() -%}\n\n    {%- if name == 'main' -%}\n      {{ log('Writing runtime {} for node \"{}\"'.format(language, model['unique_id'])) }}\n      {{ write(compiled_code) }}\n    {%- endif -%}\n    {%- if language == 'sql'-%}\n      {%- set res, table = adapter.execute(compiled_code, auto_begin=auto_begin, fetch=fetch_result) -%}\n    {%- elif language == 'python' -%}\n      {%- set res = submit_python_job(model, compiled_code) -%}\n      {#-- TODO: What should table be for python models? --#}\n      {%- set table = None -%}\n    {%- else -%}\n      {% do exceptions.raise_compiler_error(\"statement macro didn't get supported language\") %}\n    {%- endif -%}\n\n    {%- if name is not none -%}\n      {{ store_result(name, response=res, agate_table=table) }}\n    {%- endif -%}\n\n  {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3804932, "supported_languages": null}, "macro.dbt.noop_statement": {"name": "noop_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.noop_statement", "macro_sql": "{% macro noop_statement(name=None, message=None, code=None, rows_affected=None, res=None) -%}\n  {%- set sql = caller() -%}\n\n  {%- if name == 'main' -%}\n    {{ log('Writing runtime SQL for node \"{}\"'.format(model['unique_id'])) }}\n    {{ write(sql) }}\n  {%- endif -%}\n\n  {%- if name is not none -%}\n    {{ store_raw_result(name, message=message, code=code, rows_affected=rows_affected, agate_table=res) }}\n  {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.381058, "supported_languages": null}, "macro.dbt.run_query": {"name": "run_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/statement.sql", "original_file_path": "macros/etc/statement.sql", "unique_id": "macro.dbt.run_query", "macro_sql": "{% macro run_query(sql) %}\n  {% call statement(\"run_query_statement\", fetch_result=true, auto_begin=false) %}\n    {{ sql }}\n  {% endcall %}\n\n  {% do return(load_result(\"run_query_statement\").table) %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.381345, "supported_languages": null}, "macro.dbt.convert_datetime": {"name": "convert_datetime", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.convert_datetime", "macro_sql": "{% macro convert_datetime(date_str, date_fmt) %}\n\n  {% set error_msg -%}\n      The provided partition date '{{ date_str }}' does not match the expected format '{{ date_fmt }}'\n  {%- endset %}\n\n  {% set res = try_or_compiler_error(error_msg, modules.datetime.datetime.strptime, date_str.strip(), date_fmt) %}\n  {{ return(res) }}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3831549, "supported_languages": null}, "macro.dbt.dates_in_range": {"name": "dates_in_range", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.dates_in_range", "macro_sql": "{% macro dates_in_range(start_date_str, end_date_str=none, in_fmt=\"%Y%m%d\", out_fmt=\"%Y%m%d\") %}\n    {% set end_date_str = start_date_str if end_date_str is none else end_date_str %}\n\n    {% set start_date = convert_datetime(start_date_str, in_fmt) %}\n    {% set end_date = convert_datetime(end_date_str, in_fmt) %}\n\n    {% set day_count = (end_date - start_date).days %}\n    {% if day_count < 0 %}\n        {% set msg -%}\n            Partition start date is after the end date ({{ start_date }}, {{ end_date }})\n        {%- endset %}\n\n        {{ exceptions.raise_compiler_error(msg, model) }}\n    {% endif %}\n\n    {% set date_list = [] %}\n    {% for i in range(0, day_count + 1) %}\n        {% set the_date = (modules.datetime.timedelta(days=i) + start_date) %}\n        {% if not out_fmt %}\n            {% set _ = date_list.append(the_date) %}\n        {% else %}\n            {% set _ = date_list.append(the_date.strftime(out_fmt)) %}\n        {% endif %}\n    {% endfor %}\n\n    {{ return(date_list) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.convert_datetime"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.384467, "supported_languages": null}, "macro.dbt.partition_range": {"name": "partition_range", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.partition_range", "macro_sql": "{% macro partition_range(raw_partition_date, date_fmt='%Y%m%d') %}\n    {% set partition_range = (raw_partition_date | string).split(\",\") %}\n\n    {% if (partition_range | length) == 1 %}\n      {% set start_date = partition_range[0] %}\n      {% set end_date = none %}\n    {% elif (partition_range | length) == 2 %}\n      {% set start_date = partition_range[0] %}\n      {% set end_date = partition_range[1] %}\n    {% else %}\n      {{ exceptions.raise_compiler_error(\"Invalid partition time. Expected format: {Start Date}[,{End Date}]. Got: \" ~ raw_partition_date) }}\n    {% endif %}\n\n    {{ return(dates_in_range(start_date, end_date, in_fmt=date_fmt)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.dates_in_range"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.385221, "supported_languages": null}, "macro.dbt.py_current_timestring": {"name": "py_current_timestring", "resource_type": "macro", "package_name": "dbt", "path": "macros/etc/datetime.sql", "original_file_path": "macros/etc/datetime.sql", "unique_id": "macro.dbt.py_current_timestring", "macro_sql": "{% macro py_current_timestring() %}\n    {% set dt = modules.datetime.datetime.now() %}\n    {% do return(dt.strftime(\"%Y%m%d%H%M%S%f\")) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.385448, "supported_languages": null}, "macro.dbt.except": {"name": "except", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/except.sql", "original_file_path": "macros/utils/except.sql", "unique_id": "macro.dbt.except", "macro_sql": "{% macro except() %}\n  {{ return(adapter.dispatch('except', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__except"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.385685, "supported_languages": null}, "macro.dbt.default__except": {"name": "default__except", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/except.sql", "original_file_path": "macros/utils/except.sql", "unique_id": "macro.dbt.default__except", "macro_sql": "{% macro default__except() %}\n\n    except\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.38577, "supported_languages": null}, "macro.dbt.get_intervals_between": {"name": "get_intervals_between", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_spine.sql", "original_file_path": "macros/utils/date_spine.sql", "unique_id": "macro.dbt.get_intervals_between", "macro_sql": "{% macro get_intervals_between(start_date, end_date, datepart) -%}\n    {{ return(adapter.dispatch('get_intervals_between', 'dbt')(start_date, end_date, datepart)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_intervals_between"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.386504, "supported_languages": null}, "macro.dbt.default__get_intervals_between": {"name": "default__get_intervals_between", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_spine.sql", "original_file_path": "macros/utils/date_spine.sql", "unique_id": "macro.dbt.default__get_intervals_between", "macro_sql": "{% macro default__get_intervals_between(start_date, end_date, datepart) -%}\n    {%- call statement('get_intervals_between', fetch_result=True) %}\n\n        select {{ dbt.datediff(start_date, end_date, datepart) }}\n\n    {%- endcall -%}\n\n    {%- set value_list = load_result('get_intervals_between') -%}\n\n    {%- if value_list and value_list['data'] -%}\n        {%- set values = value_list['data'] | map(attribute=0) | list %}\n        {{ return(values[0]) }}\n    {%- else -%}\n        {{ return(1) }}\n    {%- endif -%}\n\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.datediff"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.387072, "supported_languages": null}, "macro.dbt.date_spine": {"name": "date_spine", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_spine.sql", "original_file_path": "macros/utils/date_spine.sql", "unique_id": "macro.dbt.date_spine", "macro_sql": "{% macro date_spine(datepart, start_date, end_date) %}\n    {{ return(adapter.dispatch('date_spine', 'dbt')(datepart, start_date, end_date)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__date_spine"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3873, "supported_languages": null}, "macro.dbt.default__date_spine": {"name": "default__date_spine", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_spine.sql", "original_file_path": "macros/utils/date_spine.sql", "unique_id": "macro.dbt.default__date_spine", "macro_sql": "{% macro default__date_spine(datepart, start_date, end_date) %}\n\n\n    {# call as follows:\n\n    date_spine(\n        \"day\",\n        \"to_date('01/01/2016', 'mm/dd/yyyy')\",\n        \"dbt.dateadd(week, 1, current_date)\"\n    ) #}\n\n\n    with rawdata as (\n\n        {{dbt.generate_series(\n            dbt.get_intervals_between(start_date, end_date, datepart)\n        )}}\n\n    ),\n\n    all_periods as (\n\n        select (\n            {{\n                dbt.dateadd(\n                    datepart,\n                    \"row_number() over (order by 1) - 1\",\n                    start_date\n                )\n            }}\n        ) as date_{{datepart}}\n        from rawdata\n\n    ),\n\n    filtered as (\n\n        select *\n        from all_periods\n        where date_{{datepart}} <= {{ end_date }}\n\n    )\n\n    select * from filtered\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.generate_series", "macro.dbt.get_intervals_between", "macro.dbt.dateadd"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3876731, "supported_languages": null}, "macro.dbt.replace": {"name": "replace", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/replace.sql", "original_file_path": "macros/utils/replace.sql", "unique_id": "macro.dbt.replace", "macro_sql": "{% macro replace(field, old_chars, new_chars) -%}\n    {{ return(adapter.dispatch('replace', 'dbt') (field, old_chars, new_chars)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__replace"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.38798, "supported_languages": null}, "macro.dbt.default__replace": {"name": "default__replace", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/replace.sql", "original_file_path": "macros/utils/replace.sql", "unique_id": "macro.dbt.default__replace", "macro_sql": "{% macro default__replace(field, old_chars, new_chars) %}\n\n    replace(\n        {{ field }},\n        {{ old_chars }},\n        {{ new_chars }}\n    )\n\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.388132, "supported_languages": null}, "macro.dbt.concat": {"name": "concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/concat.sql", "original_file_path": "macros/utils/concat.sql", "unique_id": "macro.dbt.concat", "macro_sql": "{% macro concat(fields) -%}\n  {{ return(adapter.dispatch('concat', 'dbt')(fields)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__concat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.388392, "supported_languages": null}, "macro.dbt.default__concat": {"name": "default__concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/concat.sql", "original_file_path": "macros/utils/concat.sql", "unique_id": "macro.dbt.default__concat", "macro_sql": "{% macro default__concat(fields) -%}\n    {{ fields|join(' || ') }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3885179, "supported_languages": null}, "macro.dbt.get_powers_of_two": {"name": "get_powers_of_two", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/generate_series.sql", "original_file_path": "macros/utils/generate_series.sql", "unique_id": "macro.dbt.get_powers_of_two", "macro_sql": "{% macro get_powers_of_two(upper_bound) %}\n    {{ return(adapter.dispatch('get_powers_of_two', 'dbt')(upper_bound)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_powers_of_two"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.389342, "supported_languages": null}, "macro.dbt.default__get_powers_of_two": {"name": "default__get_powers_of_two", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/generate_series.sql", "original_file_path": "macros/utils/generate_series.sql", "unique_id": "macro.dbt.default__get_powers_of_two", "macro_sql": "{% macro default__get_powers_of_two(upper_bound) %}\n\n    {% if upper_bound <= 0 %}\n    {{ exceptions.raise_compiler_error(\"upper bound must be positive\") }}\n    {% endif %}\n\n    {% for _ in range(1, 100) %}\n       {% if upper_bound <= 2 ** loop.index %}{{ return(loop.index) }}{% endif %}\n    {% endfor %}\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.389757, "supported_languages": null}, "macro.dbt.generate_series": {"name": "generate_series", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/generate_series.sql", "original_file_path": "macros/utils/generate_series.sql", "unique_id": "macro.dbt.generate_series", "macro_sql": "{% macro generate_series(upper_bound) %}\n    {{ return(adapter.dispatch('generate_series', 'dbt')(upper_bound)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__generate_series"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3899379, "supported_languages": null}, "macro.dbt.default__generate_series": {"name": "default__generate_series", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/generate_series.sql", "original_file_path": "macros/utils/generate_series.sql", "unique_id": "macro.dbt.default__generate_series", "macro_sql": "{% macro default__generate_series(upper_bound) %}\n\n    {% set n = dbt.get_powers_of_two(upper_bound) %}\n\n    with p as (\n        select 0 as generated_number union all select 1\n    ), unioned as (\n\n    select\n\n    {% for i in range(n) %}\n    p{{i}}.generated_number * power(2, {{i}})\n    {% if not loop.last %} + {% endif %}\n    {% endfor %}\n    + 1\n    as generated_number\n\n    from\n\n    {% for i in range(n) %}\n    p as p{{i}}\n    {% if not loop.last %} cross join {% endif %}\n    {% endfor %}\n\n    )\n\n    select *\n    from unioned\n    where generated_number <= {{upper_bound}}\n    order by generated_number\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_powers_of_two"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3904488, "supported_languages": null}, "macro.dbt.length": {"name": "length", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/length.sql", "original_file_path": "macros/utils/length.sql", "unique_id": "macro.dbt.length", "macro_sql": "{% macro length(expression) -%}\n    {{ return(adapter.dispatch('length', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__length"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.390711, "supported_languages": null}, "macro.dbt.default__length": {"name": "default__length", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/length.sql", "original_file_path": "macros/utils/length.sql", "unique_id": "macro.dbt.default__length", "macro_sql": "{% macro default__length(expression) %}\n\n    length(\n        {{ expression }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.390826, "supported_languages": null}, "macro.dbt.dateadd": {"name": "dateadd", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt.dateadd", "macro_sql": "{% macro dateadd(datepart, interval, from_date_or_timestamp) %}\n  {{ return(adapter.dispatch('dateadd', 'dbt')(datepart, interval, from_date_or_timestamp)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__dateadd"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.391176, "supported_languages": null}, "macro.dbt.default__dateadd": {"name": "default__dateadd", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/dateadd.sql", "original_file_path": "macros/utils/dateadd.sql", "unique_id": "macro.dbt.default__dateadd", "macro_sql": "{% macro default__dateadd(datepart, interval, from_date_or_timestamp) %}\n\n    dateadd(\n        {{ datepart }},\n        {{ interval }},\n        {{ from_date_or_timestamp }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.39133, "supported_languages": null}, "macro.dbt.intersect": {"name": "intersect", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/intersect.sql", "original_file_path": "macros/utils/intersect.sql", "unique_id": "macro.dbt.intersect", "macro_sql": "{% macro intersect() %}\n  {{ return(adapter.dispatch('intersect', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__intersect"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3915389, "supported_languages": null}, "macro.dbt.default__intersect": {"name": "default__intersect", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/intersect.sql", "original_file_path": "macros/utils/intersect.sql", "unique_id": "macro.dbt.default__intersect", "macro_sql": "{% macro default__intersect() %}\n\n    intersect\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.391679, "supported_languages": null}, "macro.dbt.escape_single_quotes": {"name": "escape_single_quotes", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/escape_single_quotes.sql", "original_file_path": "macros/utils/escape_single_quotes.sql", "unique_id": "macro.dbt.escape_single_quotes", "macro_sql": "{% macro escape_single_quotes(expression) %}\n      {{ return(adapter.dispatch('escape_single_quotes', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__escape_single_quotes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.39193, "supported_languages": null}, "macro.dbt.default__escape_single_quotes": {"name": "default__escape_single_quotes", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/escape_single_quotes.sql", "original_file_path": "macros/utils/escape_single_quotes.sql", "unique_id": "macro.dbt.default__escape_single_quotes", "macro_sql": "{% macro default__escape_single_quotes(expression) -%}\n{{ expression | replace(\"'\",\"''\") }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3920588, "supported_languages": null}, "macro.dbt.right": {"name": "right", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/right.sql", "original_file_path": "macros/utils/right.sql", "unique_id": "macro.dbt.right", "macro_sql": "{% macro right(string_text, length_expression) -%}\n    {{ return(adapter.dispatch('right', 'dbt') (string_text, length_expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__right"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3923478, "supported_languages": null}, "macro.dbt.default__right": {"name": "default__right", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/right.sql", "original_file_path": "macros/utils/right.sql", "unique_id": "macro.dbt.default__right", "macro_sql": "{% macro default__right(string_text, length_expression) %}\n\n    right(\n        {{ string_text }},\n        {{ length_expression }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.392482, "supported_languages": null}, "macro.dbt.listagg": {"name": "listagg", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt.listagg", "macro_sql": "{% macro listagg(measure, delimiter_text=\"','\", order_by_clause=none, limit_num=none) -%}\n    {{ return(adapter.dispatch('listagg', 'dbt') (measure, delimiter_text, order_by_clause, limit_num)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__listagg"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3931258, "supported_languages": null}, "macro.dbt.default__listagg": {"name": "default__listagg", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/listagg.sql", "original_file_path": "macros/utils/listagg.sql", "unique_id": "macro.dbt.default__listagg", "macro_sql": "{% macro default__listagg(measure, delimiter_text, order_by_clause, limit_num) -%}\n\n    {% if limit_num -%}\n    array_to_string(\n        array_slice(\n            array_agg(\n                {{ measure }}\n            ){% if order_by_clause -%}\n            within group ({{ order_by_clause }})\n            {%- endif %}\n            ,0\n            ,{{ limit_num }}\n        ),\n        {{ delimiter_text }}\n        )\n    {%- else %}\n    listagg(\n        {{ measure }},\n        {{ delimiter_text }}\n        )\n        {% if order_by_clause -%}\n        within group ({{ order_by_clause }})\n        {%- endif %}\n    {%- endif %}\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3935292, "supported_languages": null}, "macro.dbt.datediff": {"name": "datediff", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt.datediff", "macro_sql": "{% macro datediff(first_date, second_date, datepart) %}\n  {{ return(adapter.dispatch('datediff', 'dbt')(first_date, second_date, datepart)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__datediff"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.393843, "supported_languages": null}, "macro.dbt.default__datediff": {"name": "default__datediff", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/datediff.sql", "original_file_path": "macros/utils/datediff.sql", "unique_id": "macro.dbt.default__datediff", "macro_sql": "{% macro default__datediff(first_date, second_date, datepart) -%}\n\n    datediff(\n        {{ datepart }},\n        {{ first_date }},\n        {{ second_date }}\n        )\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.394003, "supported_languages": null}, "macro.dbt.safe_cast": {"name": "safe_cast", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/safe_cast.sql", "original_file_path": "macros/utils/safe_cast.sql", "unique_id": "macro.dbt.safe_cast", "macro_sql": "{% macro safe_cast(field, type) %}\n  {{ return(adapter.dispatch('safe_cast', 'dbt') (field, type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__safe_cast"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.394272, "supported_languages": null}, "macro.dbt.default__safe_cast": {"name": "default__safe_cast", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/safe_cast.sql", "original_file_path": "macros/utils/safe_cast.sql", "unique_id": "macro.dbt.default__safe_cast", "macro_sql": "{% macro default__safe_cast(field, type) %}\n    {# most databases don't support this function yet\n    so we just need to use cast #}\n    cast({{field}} as {{type}})\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3944068, "supported_languages": null}, "macro.dbt.hash": {"name": "hash", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/hash.sql", "original_file_path": "macros/utils/hash.sql", "unique_id": "macro.dbt.hash", "macro_sql": "{% macro hash(field) -%}\n  {{ return(adapter.dispatch('hash', 'dbt') (field)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__hash"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.394668, "supported_languages": null}, "macro.dbt.default__hash": {"name": "default__hash", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/hash.sql", "original_file_path": "macros/utils/hash.sql", "unique_id": "macro.dbt.default__hash", "macro_sql": "{% macro default__hash(field) -%}\n    md5(cast({{ field }} as {{ api.Column.translate_type('string') }}))\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.39483, "supported_languages": null}, "macro.dbt.cast_bool_to_text": {"name": "cast_bool_to_text", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/cast_bool_to_text.sql", "original_file_path": "macros/utils/cast_bool_to_text.sql", "unique_id": "macro.dbt.cast_bool_to_text", "macro_sql": "{% macro cast_bool_to_text(field) %}\n  {{ adapter.dispatch('cast_bool_to_text', 'dbt') (field) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__cast_bool_to_text"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.395061, "supported_languages": null}, "macro.dbt.default__cast_bool_to_text": {"name": "default__cast_bool_to_text", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/cast_bool_to_text.sql", "original_file_path": "macros/utils/cast_bool_to_text.sql", "unique_id": "macro.dbt.default__cast_bool_to_text", "macro_sql": "{% macro default__cast_bool_to_text(field) %}\n    cast({{ field }} as {{ api.Column.translate_type('string') }})\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3952289, "supported_languages": null}, "macro.dbt.any_value": {"name": "any_value", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt.any_value", "macro_sql": "{% macro any_value(expression) -%}\n    {{ return(adapter.dispatch('any_value', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__any_value"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3954592, "supported_languages": null}, "macro.dbt.default__any_value": {"name": "default__any_value", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/any_value.sql", "original_file_path": "macros/utils/any_value.sql", "unique_id": "macro.dbt.default__any_value", "macro_sql": "{% macro default__any_value(expression) -%}\n\n    any_value({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3955572, "supported_languages": null}, "macro.dbt.position": {"name": "position", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/position.sql", "original_file_path": "macros/utils/position.sql", "unique_id": "macro.dbt.position", "macro_sql": "{% macro position(substring_text, string_text) -%}\n    {{ return(adapter.dispatch('position', 'dbt') (substring_text, string_text)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__position"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.395829, "supported_languages": null}, "macro.dbt.default__position": {"name": "default__position", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/position.sql", "original_file_path": "macros/utils/position.sql", "unique_id": "macro.dbt.default__position", "macro_sql": "{% macro default__position(substring_text, string_text) %}\n\n    position(\n        {{ substring_text }} in {{ string_text }}\n    )\n\n{%- endmacro -%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.395956, "supported_languages": null}, "macro.dbt.string_literal": {"name": "string_literal", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/literal.sql", "original_file_path": "macros/utils/literal.sql", "unique_id": "macro.dbt.string_literal", "macro_sql": "{%- macro string_literal(value) -%}\n  {{ return(adapter.dispatch('string_literal', 'dbt') (value)) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__string_literal"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.396199, "supported_languages": null}, "macro.dbt.default__string_literal": {"name": "default__string_literal", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/literal.sql", "original_file_path": "macros/utils/literal.sql", "unique_id": "macro.dbt.default__string_literal", "macro_sql": "{% macro default__string_literal(value) -%}\n    '{{ value }}'\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.396354, "supported_languages": null}, "macro.dbt.type_string": {"name": "type_string", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_string", "macro_sql": "\n\n{%- macro type_string() -%}\n  {{ return(adapter.dispatch('type_string', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_string"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3972638, "supported_languages": null}, "macro.dbt.default__type_string": {"name": "default__type_string", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_string", "macro_sql": "{% macro default__type_string() %}\n    {{ return(api.Column.translate_type(\"string\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3974159, "supported_languages": null}, "macro.dbt.type_timestamp": {"name": "type_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_timestamp", "macro_sql": "\n\n{%- macro type_timestamp() -%}\n  {{ return(adapter.dispatch('type_timestamp', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3975801, "supported_languages": null}, "macro.dbt.default__type_timestamp": {"name": "default__type_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_timestamp", "macro_sql": "{% macro default__type_timestamp() %}\n    {{ return(api.Column.translate_type(\"timestamp\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.397724, "supported_languages": null}, "macro.dbt.type_float": {"name": "type_float", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_float", "macro_sql": "\n\n{%- macro type_float() -%}\n  {{ return(adapter.dispatch('type_float', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_float"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.397878, "supported_languages": null}, "macro.dbt.default__type_float": {"name": "default__type_float", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_float", "macro_sql": "{% macro default__type_float() %}\n    {{ return(api.Column.translate_type(\"float\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.398019, "supported_languages": null}, "macro.dbt.type_numeric": {"name": "type_numeric", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_numeric", "macro_sql": "\n\n{%- macro type_numeric() -%}\n  {{ return(adapter.dispatch('type_numeric', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_numeric"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.398171, "supported_languages": null}, "macro.dbt.default__type_numeric": {"name": "default__type_numeric", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_numeric", "macro_sql": "{% macro default__type_numeric() %}\n    {{ return(api.Column.numeric_type(\"numeric\", 28, 6)) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.398336, "supported_languages": null}, "macro.dbt.type_bigint": {"name": "type_bigint", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_bigint", "macro_sql": "\n\n{%- macro type_bigint() -%}\n  {{ return(adapter.dispatch('type_bigint', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_bigint"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.398498, "supported_languages": null}, "macro.dbt.default__type_bigint": {"name": "default__type_bigint", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_bigint", "macro_sql": "{% macro default__type_bigint() %}\n    {{ return(api.Column.translate_type(\"bigint\")) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.398651, "supported_languages": null}, "macro.dbt.type_int": {"name": "type_int", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_int", "macro_sql": "\n\n{%- macro type_int() -%}\n  {{ return(adapter.dispatch('type_int', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_int"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3988109, "supported_languages": null}, "macro.dbt.default__type_int": {"name": "default__type_int", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_int", "macro_sql": "{%- macro default__type_int() -%}\n  {{ return(api.Column.translate_type(\"integer\")) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3989499, "supported_languages": null}, "macro.dbt.type_boolean": {"name": "type_boolean", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.type_boolean", "macro_sql": "\n\n{%- macro type_boolean() -%}\n  {{ return(adapter.dispatch('type_boolean', 'dbt')()) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.default__type_boolean"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.399112, "supported_languages": null}, "macro.dbt.default__type_boolean": {"name": "default__type_boolean", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/data_types.sql", "original_file_path": "macros/utils/data_types.sql", "unique_id": "macro.dbt.default__type_boolean", "macro_sql": "{%- macro default__type_boolean() -%}\n  {{ return(api.Column.translate_type(\"boolean\")) }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.399254, "supported_languages": null}, "macro.dbt.array_concat": {"name": "array_concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_concat.sql", "original_file_path": "macros/utils/array_concat.sql", "unique_id": "macro.dbt.array_concat", "macro_sql": "{% macro array_concat(array_1, array_2) -%}\n  {{ return(adapter.dispatch('array_concat', 'dbt')(array_1, array_2)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_concat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.3995352, "supported_languages": null}, "macro.dbt.default__array_concat": {"name": "default__array_concat", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_concat.sql", "original_file_path": "macros/utils/array_concat.sql", "unique_id": "macro.dbt.default__array_concat", "macro_sql": "{% macro default__array_concat(array_1, array_2) -%}\n    array_cat({{ array_1 }}, {{ array_2 }})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.39966, "supported_languages": null}, "macro.dbt.bool_or": {"name": "bool_or", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/bool_or.sql", "original_file_path": "macros/utils/bool_or.sql", "unique_id": "macro.dbt.bool_or", "macro_sql": "{% macro bool_or(expression) -%}\n    {{ return(adapter.dispatch('bool_or', 'dbt') (expression)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__bool_or"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.399913, "supported_languages": null}, "macro.dbt.default__bool_or": {"name": "default__bool_or", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/bool_or.sql", "original_file_path": "macros/utils/bool_or.sql", "unique_id": "macro.dbt.default__bool_or", "macro_sql": "{% macro default__bool_or(expression) -%}\n\n    bool_or({{ expression }})\n\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.400013, "supported_languages": null}, "macro.dbt.last_day": {"name": "last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.last_day", "macro_sql": "{% macro last_day(date, datepart) %}\n  {{ return(adapter.dispatch('last_day', 'dbt') (date, datepart)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4003358, "supported_languages": null}, "macro.dbt.default_last_day": {"name": "default_last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.default_last_day", "macro_sql": "\n\n{%- macro default_last_day(date, datepart) -%}\n    cast(\n        {{dbt.dateadd('day', '-1',\n        dbt.dateadd(datepart, '1', dbt.date_trunc(datepart, date))\n        )}}\n        as date)\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt.dateadd", "macro.dbt.date_trunc"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4006479, "supported_languages": null}, "macro.dbt.default__last_day": {"name": "default__last_day", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/last_day.sql", "original_file_path": "macros/utils/last_day.sql", "unique_id": "macro.dbt.default__last_day", "macro_sql": "{% macro default__last_day(date, datepart) -%}\n    {{dbt.default_last_day(date, datepart)}}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default_last_day"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.400789, "supported_languages": null}, "macro.dbt.split_part": {"name": "split_part", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt.split_part", "macro_sql": "{% macro split_part(string_text, delimiter_text, part_number) %}\n  {{ return(adapter.dispatch('split_part', 'dbt') (string_text, delimiter_text, part_number)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__split_part"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.401296, "supported_languages": null}, "macro.dbt.default__split_part": {"name": "default__split_part", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt.default__split_part", "macro_sql": "{% macro default__split_part(string_text, delimiter_text, part_number) %}\n\n    split_part(\n        {{ string_text }},\n        {{ delimiter_text }},\n        {{ part_number }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4014568, "supported_languages": null}, "macro.dbt._split_part_negative": {"name": "_split_part_negative", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/split_part.sql", "original_file_path": "macros/utils/split_part.sql", "unique_id": "macro.dbt._split_part_negative", "macro_sql": "{% macro _split_part_negative(string_text, delimiter_text, part_number) %}\n\n    split_part(\n        {{ string_text }},\n        {{ delimiter_text }},\n          length({{ string_text }})\n          - length(\n              replace({{ string_text }},  {{ delimiter_text }}, '')\n          ) + 2 + {{ part_number }}\n        )\n\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.401684, "supported_languages": null}, "macro.dbt.date_trunc": {"name": "date_trunc", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_trunc.sql", "original_file_path": "macros/utils/date_trunc.sql", "unique_id": "macro.dbt.date_trunc", "macro_sql": "{% macro date_trunc(datepart, date) -%}\n  {{ return(adapter.dispatch('date_trunc', 'dbt') (datepart, date)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__date_trunc"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.40197, "supported_languages": null}, "macro.dbt.default__date_trunc": {"name": "default__date_trunc", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/date_trunc.sql", "original_file_path": "macros/utils/date_trunc.sql", "unique_id": "macro.dbt.default__date_trunc", "macro_sql": "{% macro default__date_trunc(datepart, date) -%}\n    date_trunc('{{datepart}}', {{date}})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.402091, "supported_languages": null}, "macro.dbt.array_construct": {"name": "array_construct", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_construct.sql", "original_file_path": "macros/utils/array_construct.sql", "unique_id": "macro.dbt.array_construct", "macro_sql": "{% macro array_construct(inputs=[], data_type=api.Column.translate_type('integer')) -%}\n  {{ return(adapter.dispatch('array_construct', 'dbt')(inputs, data_type)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_construct"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.402441, "supported_languages": null}, "macro.dbt.default__array_construct": {"name": "default__array_construct", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_construct.sql", "original_file_path": "macros/utils/array_construct.sql", "unique_id": "macro.dbt.default__array_construct", "macro_sql": "{% macro default__array_construct(inputs, data_type) -%}\n    {% if inputs|length > 0 %}\n    array[ {{ inputs|join(' , ') }} ]\n    {% else %}\n    array[]::{{data_type}}[]\n    {% endif %}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.402674, "supported_languages": null}, "macro.dbt.array_append": {"name": "array_append", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_append.sql", "original_file_path": "macros/utils/array_append.sql", "unique_id": "macro.dbt.array_append", "macro_sql": "{% macro array_append(array, new_element) -%}\n  {{ return(adapter.dispatch('array_append', 'dbt')(array, new_element)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__array_append"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4029598, "supported_languages": null}, "macro.dbt.default__array_append": {"name": "default__array_append", "resource_type": "macro", "package_name": "dbt", "path": "macros/utils/array_append.sql", "original_file_path": "macros/utils/array_append.sql", "unique_id": "macro.dbt.default__array_append", "macro_sql": "{% macro default__array_append(array, new_element) -%}\n    array_append({{ array }}, {{ new_element }})\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4030888, "supported_languages": null}, "macro.dbt.create_schema": {"name": "create_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.create_schema", "macro_sql": "{% macro create_schema(relation) -%}\n  {{ adapter.dispatch('create_schema', 'dbt')(relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__create_schema"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.403466, "supported_languages": null}, "macro.dbt.default__create_schema": {"name": "default__create_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.default__create_schema", "macro_sql": "{% macro default__create_schema(relation) -%}\n  {%- call statement('create_schema') -%}\n    create schema if not exists {{ relation.without_identifier() }}\n  {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.403645, "supported_languages": null}, "macro.dbt.drop_schema": {"name": "drop_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.drop_schema", "macro_sql": "{% macro drop_schema(relation) -%}\n  {{ adapter.dispatch('drop_schema', 'dbt')(relation) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__drop_schema"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.403808, "supported_languages": null}, "macro.dbt.default__drop_schema": {"name": "default__drop_schema", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/schema.sql", "original_file_path": "macros/adapters/schema.sql", "unique_id": "macro.dbt.default__drop_schema", "macro_sql": "{% macro default__drop_schema(relation) -%}\n  {%- call statement('drop_schema') -%}\n    drop schema if exists {{ relation.without_identifier() }} cascade\n  {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.40399, "supported_languages": null}, "macro.dbt.current_timestamp": {"name": "current_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp", "macro_sql": "{%- macro current_timestamp() -%}\n    {{ adapter.dispatch('current_timestamp', 'dbt')() }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.404497, "supported_languages": null}, "macro.dbt.default__current_timestamp": {"name": "default__current_timestamp", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp", "macro_sql": "{% macro default__current_timestamp() -%}\n  {{ exceptions.raise_not_implemented(\n    'current_timestamp macro not implemented for adapter ' + adapter.type()) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.404661, "supported_languages": null}, "macro.dbt.snapshot_get_time": {"name": "snapshot_get_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.snapshot_get_time", "macro_sql": "\n\n{%- macro snapshot_get_time() -%}\n    {{ adapter.dispatch('snapshot_get_time', 'dbt')() }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__snapshot_get_time"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.404811, "supported_languages": null}, "macro.dbt.default__snapshot_get_time": {"name": "default__snapshot_get_time", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__snapshot_get_time", "macro_sql": "{% macro default__snapshot_get_time() %}\n    {{ current_timestamp() }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.404914, "supported_languages": null}, "macro.dbt.current_timestamp_backcompat": {"name": "current_timestamp_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp_backcompat", "macro_sql": "{% macro current_timestamp_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__current_timestamp_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4050748, "supported_languages": null}, "macro.dbt.default__current_timestamp_backcompat": {"name": "default__current_timestamp_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp_backcompat", "macro_sql": "{% macro default__current_timestamp_backcompat() %}\n    current_timestamp::timestamp\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.405149, "supported_languages": null}, "macro.dbt.current_timestamp_in_utc_backcompat": {"name": "current_timestamp_in_utc_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.current_timestamp_in_utc_backcompat", "macro_sql": "{% macro current_timestamp_in_utc_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_in_utc_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__current_timestamp_in_utc_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.405377, "supported_languages": null}, "macro.dbt.default__current_timestamp_in_utc_backcompat": {"name": "default__current_timestamp_in_utc_backcompat", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/timestamps.sql", "original_file_path": "macros/adapters/timestamps.sql", "unique_id": "macro.dbt.default__current_timestamp_in_utc_backcompat", "macro_sql": "{% macro default__current_timestamp_in_utc_backcompat() %}\n    {{ return(adapter.dispatch('current_timestamp_backcompat', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.current_timestamp_backcompat", "macro.dbt.default__current_timestamp_backcompat"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4055412, "supported_languages": null}, "macro.dbt.get_create_index_sql": {"name": "get_create_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.get_create_index_sql", "macro_sql": "{% macro get_create_index_sql(relation, index_dict) -%}\n  {{ return(adapter.dispatch('get_create_index_sql', 'dbt')(relation, index_dict)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_create_index_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.406538, "supported_languages": null}, "macro.dbt.default__get_create_index_sql": {"name": "default__get_create_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__get_create_index_sql", "macro_sql": "{% macro default__get_create_index_sql(relation, index_dict) -%}\n  {% do return(None) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.406691, "supported_languages": null}, "macro.dbt.create_indexes": {"name": "create_indexes", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.create_indexes", "macro_sql": "{% macro create_indexes(relation) -%}\n  {{ adapter.dispatch('create_indexes', 'dbt')(relation) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__create_indexes"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4068449, "supported_languages": null}, "macro.dbt.default__create_indexes": {"name": "default__create_indexes", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__create_indexes", "macro_sql": "{% macro default__create_indexes(relation) -%}\n  {%- set _indexes = config.get('indexes', default=[]) -%}\n\n  {% for _index_dict in _indexes %}\n    {% set create_index_sql = get_create_index_sql(relation, _index_dict) %}\n    {% if create_index_sql %}\n      {% do run_query(create_index_sql) %}\n    {% endif %}\n  {% endfor %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_create_index_sql", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4072719, "supported_languages": null}, "macro.dbt.get_drop_index_sql": {"name": "get_drop_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.get_drop_index_sql", "macro_sql": "{% macro get_drop_index_sql(relation, index_name) -%}\n    {{ adapter.dispatch('get_drop_index_sql', 'dbt')(relation, index_name) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_drop_index_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4074728, "supported_languages": null}, "macro.dbt.default__get_drop_index_sql": {"name": "default__get_drop_index_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__get_drop_index_sql", "macro_sql": "{% macro default__get_drop_index_sql(relation, index_name) -%}\n    {{ exceptions.raise_compiler_error(\"`get_drop_index_sql has not been implemented for this adapter.\") }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.407617, "supported_languages": null}, "macro.dbt.get_show_indexes_sql": {"name": "get_show_indexes_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.get_show_indexes_sql", "macro_sql": "{% macro get_show_indexes_sql(relation) -%}\n    {{ adapter.dispatch('get_show_indexes_sql', 'dbt')(relation) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_show_indexes_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4077818, "supported_languages": null}, "macro.dbt.default__get_show_indexes_sql": {"name": "default__get_show_indexes_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/indexes.sql", "original_file_path": "macros/adapters/indexes.sql", "unique_id": "macro.dbt.default__get_show_indexes_sql", "macro_sql": "{% macro default__get_show_indexes_sql(relation) -%}\n    {{ exceptions.raise_compiler_error(\"`get_show_indexes_sql has not been implemented for this adapter.\") }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4079201, "supported_languages": null}, "macro.dbt.make_intermediate_relation": {"name": "make_intermediate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_intermediate_relation", "macro_sql": "{% macro make_intermediate_relation(base_relation, suffix='__dbt_tmp') %}\n  {{ return(adapter.dispatch('make_intermediate_relation', 'dbt')(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_intermediate_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4099782, "supported_languages": null}, "macro.dbt.default__make_intermediate_relation": {"name": "default__make_intermediate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_intermediate_relation", "macro_sql": "{% macro default__make_intermediate_relation(base_relation, suffix) %}\n    {{ return(default__make_temp_relation(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_temp_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.410145, "supported_languages": null}, "macro.dbt.make_temp_relation": {"name": "make_temp_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_temp_relation", "macro_sql": "{% macro make_temp_relation(base_relation, suffix='__dbt_tmp') %}\n  {{ return(adapter.dispatch('make_temp_relation', 'dbt')(base_relation, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__make_temp_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.410369, "supported_languages": null}, "macro.dbt.default__make_temp_relation": {"name": "default__make_temp_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_temp_relation", "macro_sql": "{% macro default__make_temp_relation(base_relation, suffix) %}\n    {%- set temp_identifier = base_relation.identifier ~ suffix -%}\n    {%- set temp_relation = base_relation.incorporate(\n                                path={\"identifier\": temp_identifier}) -%}\n\n    {{ return(temp_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.410657, "supported_languages": null}, "macro.dbt.make_backup_relation": {"name": "make_backup_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.make_backup_relation", "macro_sql": "{% macro make_backup_relation(base_relation, backup_relation_type, suffix='__dbt_backup') %}\n    {{ return(adapter.dispatch('make_backup_relation', 'dbt')(base_relation, backup_relation_type, suffix)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__make_backup_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.410888, "supported_languages": null}, "macro.dbt.default__make_backup_relation": {"name": "default__make_backup_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__make_backup_relation", "macro_sql": "{% macro default__make_backup_relation(base_relation, backup_relation_type, suffix) %}\n    {%- set backup_identifier = base_relation.identifier ~ suffix -%}\n    {%- set backup_relation = base_relation.incorporate(\n                                  path={\"identifier\": backup_identifier},\n                                  type=backup_relation_type\n    ) -%}\n    {{ return(backup_relation) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.411212, "supported_languages": null}, "macro.dbt.truncate_relation": {"name": "truncate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.truncate_relation", "macro_sql": "{% macro truncate_relation(relation) -%}\n  {{ return(adapter.dispatch('truncate_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__truncate_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.411399, "supported_languages": null}, "macro.dbt.default__truncate_relation": {"name": "default__truncate_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__truncate_relation", "macro_sql": "{% macro default__truncate_relation(relation) -%}\n  {% call statement('truncate_relation') -%}\n    truncate table {{ relation }}\n  {%- endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4115698, "supported_languages": null}, "macro.dbt.get_or_create_relation": {"name": "get_or_create_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.get_or_create_relation", "macro_sql": "{% macro get_or_create_relation(database, schema, identifier, type) -%}\n  {{ return(adapter.dispatch('get_or_create_relation', 'dbt')(database, schema, identifier, type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_or_create_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.411826, "supported_languages": null}, "macro.dbt.default__get_or_create_relation": {"name": "default__get_or_create_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.default__get_or_create_relation", "macro_sql": "{% macro default__get_or_create_relation(database, schema, identifier, type) %}\n  {%- set target_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) %}\n\n  {% if target_relation %}\n    {% do return([true, target_relation]) %}\n  {% endif %}\n\n  {%- set new_relation = api.Relation.create(\n      database=database,\n      schema=schema,\n      identifier=identifier,\n      type=type\n  ) -%}\n  {% do return([false, new_relation]) %}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4124212, "supported_languages": null}, "macro.dbt.load_cached_relation": {"name": "load_cached_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.load_cached_relation", "macro_sql": "{% macro load_cached_relation(relation) %}\n  {% do return(adapter.get_relation(\n    database=relation.database,\n    schema=relation.schema,\n    identifier=relation.identifier\n  )) -%}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.412653, "supported_languages": null}, "macro.dbt.load_relation": {"name": "load_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/relation.sql", "original_file_path": "macros/adapters/relation.sql", "unique_id": "macro.dbt.load_relation", "macro_sql": "{% macro load_relation(relation) %}\n    {{ return(load_cached_relation(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.load_cached_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.412787, "supported_languages": null}, "macro.dbt.collect_freshness": {"name": "collect_freshness", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/freshness.sql", "original_file_path": "macros/adapters/freshness.sql", "unique_id": "macro.dbt.collect_freshness", "macro_sql": "{% macro collect_freshness(source, loaded_at_field, filter) %}\n  {{ return(adapter.dispatch('collect_freshness', 'dbt')(source, loaded_at_field, filter))}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__collect_freshness"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.413215, "supported_languages": null}, "macro.dbt.default__collect_freshness": {"name": "default__collect_freshness", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/freshness.sql", "original_file_path": "macros/adapters/freshness.sql", "unique_id": "macro.dbt.default__collect_freshness", "macro_sql": "{% macro default__collect_freshness(source, loaded_at_field, filter) %}\n  {% call statement('collect_freshness', fetch_result=True, auto_begin=False) -%}\n    select\n      max({{ loaded_at_field }}) as max_loaded_at,\n      {{ current_timestamp() }} as snapshotted_at\n    from {{ source }}\n    {% if filter %}\n    where {{ filter }}\n    {% endif %}\n  {% endcall %}\n  {{ return(load_result('collect_freshness')) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.current_timestamp"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4136178, "supported_languages": null}, "macro.dbt.validate_sql": {"name": "validate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/validate_sql.sql", "original_file_path": "macros/adapters/validate_sql.sql", "unique_id": "macro.dbt.validate_sql", "macro_sql": "{% macro validate_sql(sql) -%}\n  {{ return(adapter.dispatch('validate_sql', 'dbt')(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__validate_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.413891, "supported_languages": null}, "macro.dbt.default__validate_sql": {"name": "default__validate_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/validate_sql.sql", "original_file_path": "macros/adapters/validate_sql.sql", "unique_id": "macro.dbt.default__validate_sql", "macro_sql": "{% macro default__validate_sql(sql) -%}\n  {% call statement('validate_sql') -%}\n    explain {{ sql }}\n  {% endcall %}\n  {{ return(load_result('validate_sql')) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.414112, "supported_languages": null}, "macro.dbt.copy_grants": {"name": "copy_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.copy_grants", "macro_sql": "{% macro copy_grants() %}\n    {{ return(adapter.dispatch('copy_grants', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__copy_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.41579, "supported_languages": null}, "macro.dbt.default__copy_grants": {"name": "default__copy_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__copy_grants", "macro_sql": "{% macro default__copy_grants() %}\n    {{ return(True) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4159071, "supported_languages": null}, "macro.dbt.support_multiple_grantees_per_dcl_statement": {"name": "support_multiple_grantees_per_dcl_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.support_multiple_grantees_per_dcl_statement", "macro_sql": "{% macro support_multiple_grantees_per_dcl_statement() %}\n    {{ return(adapter.dispatch('support_multiple_grantees_per_dcl_statement', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__support_multiple_grantees_per_dcl_statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.41607, "supported_languages": null}, "macro.dbt.default__support_multiple_grantees_per_dcl_statement": {"name": "default__support_multiple_grantees_per_dcl_statement", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__support_multiple_grantees_per_dcl_statement", "macro_sql": "\n\n{%- macro default__support_multiple_grantees_per_dcl_statement() -%}\n    {{ return(True) }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4163651, "supported_languages": null}, "macro.dbt.should_revoke": {"name": "should_revoke", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.should_revoke", "macro_sql": "{% macro should_revoke(existing_relation, full_refresh_mode=True) %}\n\n    {% if not existing_relation %}\n        {#-- The table doesn't already exist, so no grants to copy over --#}\n        {{ return(False) }}\n    {% elif full_refresh_mode %}\n        {#-- The object is being REPLACED -- whether grants are copied over depends on the value of user config --#}\n        {{ return(copy_grants()) }}\n    {% else %}\n        {#-- The table is being merged/upserted/inserted -- grants will be carried over --#}\n        {{ return(True) }}\n    {% endif %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.copy_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.416749, "supported_languages": null}, "macro.dbt.get_show_grant_sql": {"name": "get_show_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_show_grant_sql", "macro_sql": "{% macro get_show_grant_sql(relation) %}\n    {{ return(adapter.dispatch(\"get_show_grant_sql\", \"dbt\")(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_show_grant_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.416945, "supported_languages": null}, "macro.dbt.default__get_show_grant_sql": {"name": "default__get_show_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_show_grant_sql", "macro_sql": "{% macro default__get_show_grant_sql(relation) %}\n    show grants on {{ relation }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.417047, "supported_languages": null}, "macro.dbt.get_grant_sql": {"name": "get_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_grant_sql", "macro_sql": "{% macro get_grant_sql(relation, privilege, grantees) %}\n    {{ return(adapter.dispatch('get_grant_sql', 'dbt')(relation, privilege, grantees)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_grant_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.417266, "supported_languages": null}, "macro.dbt.default__get_grant_sql": {"name": "default__get_grant_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_grant_sql", "macro_sql": "\n\n{%- macro default__get_grant_sql(relation, privilege, grantees) -%}\n    grant {{ privilege }} on {{ relation }} to {{ grantees | join(', ') }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.417452, "supported_languages": null}, "macro.dbt.get_revoke_sql": {"name": "get_revoke_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_revoke_sql", "macro_sql": "{% macro get_revoke_sql(relation, privilege, grantees) %}\n    {{ return(adapter.dispatch('get_revoke_sql', 'dbt')(relation, privilege, grantees)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_revoke_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.417669, "supported_languages": null}, "macro.dbt.default__get_revoke_sql": {"name": "default__get_revoke_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_revoke_sql", "macro_sql": "\n\n{%- macro default__get_revoke_sql(relation, privilege, grantees) -%}\n    revoke {{ privilege }} on {{ relation }} from {{ grantees | join(', ') }}\n{%- endmacro -%}\n\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.417844, "supported_languages": null}, "macro.dbt.get_dcl_statement_list": {"name": "get_dcl_statement_list", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.get_dcl_statement_list", "macro_sql": "{% macro get_dcl_statement_list(relation, grant_config, get_dcl_macro) %}\n    {{ return(adapter.dispatch('get_dcl_statement_list', 'dbt')(relation, grant_config, get_dcl_macro)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_dcl_statement_list"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.41807, "supported_languages": null}, "macro.dbt.default__get_dcl_statement_list": {"name": "default__get_dcl_statement_list", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__get_dcl_statement_list", "macro_sql": "\n\n{%- macro default__get_dcl_statement_list(relation, grant_config, get_dcl_macro) -%}\n    {#\n      -- Unpack grant_config into specific privileges and the set of users who need them granted/revoked.\n      -- Depending on whether this database supports multiple grantees per statement, pass in the list of\n      -- all grantees per privilege, or (if not) template one statement per privilege-grantee pair.\n      -- `get_dcl_macro` will be either `get_grant_sql` or `get_revoke_sql`\n    #}\n    {%- set dcl_statements = [] -%}\n    {%- for privilege, grantees in grant_config.items() %}\n        {%- if support_multiple_grantees_per_dcl_statement() and grantees -%}\n          {%- set dcl = get_dcl_macro(relation, privilege, grantees) -%}\n          {%- do dcl_statements.append(dcl) -%}\n        {%- else -%}\n          {%- for grantee in grantees -%}\n              {% set dcl = get_dcl_macro(relation, privilege, [grantee]) %}\n              {%- do dcl_statements.append(dcl) -%}\n          {% endfor -%}\n        {%- endif -%}\n    {%- endfor -%}\n    {{ return(dcl_statements) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.support_multiple_grantees_per_dcl_statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.418817, "supported_languages": null}, "macro.dbt.call_dcl_statements": {"name": "call_dcl_statements", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.call_dcl_statements", "macro_sql": "{% macro call_dcl_statements(dcl_statement_list) %}\n    {{ return(adapter.dispatch(\"call_dcl_statements\", \"dbt\")(dcl_statement_list)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__call_dcl_statements"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.418998, "supported_languages": null}, "macro.dbt.default__call_dcl_statements": {"name": "default__call_dcl_statements", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__call_dcl_statements", "macro_sql": "{% macro default__call_dcl_statements(dcl_statement_list) %}\n    {#\n      -- By default, supply all grant + revoke statements in a single semicolon-separated block,\n      -- so that they're all processed together.\n\n      -- Some databases do not support this. Those adapters will need to override this macro\n      -- to run each statement individually.\n    #}\n    {% call statement('grants') %}\n        {% for dcl_statement in dcl_statement_list %}\n            {{ dcl_statement }};\n        {% endfor %}\n    {% endcall %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4192362, "supported_languages": null}, "macro.dbt.apply_grants": {"name": "apply_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.apply_grants", "macro_sql": "{% macro apply_grants(relation, grant_config, should_revoke) %}\n    {{ return(adapter.dispatch(\"apply_grants\", \"dbt\")(relation, grant_config, should_revoke)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__apply_grants"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4194639, "supported_languages": null}, "macro.dbt.default__apply_grants": {"name": "default__apply_grants", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/apply_grants.sql", "original_file_path": "macros/adapters/apply_grants.sql", "unique_id": "macro.dbt.default__apply_grants", "macro_sql": "{% macro default__apply_grants(relation, grant_config, should_revoke=True) %}\n    {#-- If grant_config is {} or None, this is a no-op --#}\n    {% if grant_config %}\n        {% if should_revoke %}\n            {#-- We think previous grants may have carried over --#}\n            {#-- Show current grants and calculate diffs --#}\n            {% set current_grants_table = run_query(get_show_grant_sql(relation)) %}\n            {% set current_grants_dict = adapter.standardize_grants_dict(current_grants_table) %}\n            {% set needs_granting = diff_of_two_dicts(grant_config, current_grants_dict) %}\n            {% set needs_revoking = diff_of_two_dicts(current_grants_dict, grant_config) %}\n            {% if not (needs_granting or needs_revoking) %}\n                {{ log('On ' ~ relation ~': All grants are in place, no revocation or granting needed.')}}\n            {% endif %}\n        {% else %}\n            {#-- We don't think there's any chance of previous grants having carried over. --#}\n            {#-- Jump straight to granting what the user has configured. --#}\n            {% set needs_revoking = {} %}\n            {% set needs_granting = grant_config %}\n        {% endif %}\n        {% if needs_granting or needs_revoking %}\n            {% set revoke_statement_list = get_dcl_statement_list(relation, needs_revoking, get_revoke_sql) %}\n            {% set grant_statement_list = get_dcl_statement_list(relation, needs_granting, get_grant_sql) %}\n            {% set dcl_statement_list = revoke_statement_list + grant_statement_list %}\n            {% if dcl_statement_list %}\n                {{ call_dcl_statements(dcl_statement_list) }}\n            {% endif %}\n        {% endif %}\n    {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query", "macro.dbt.get_show_grant_sql", "macro.dbt.get_dcl_statement_list", "macro.dbt.call_dcl_statements"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.420606, "supported_languages": null}, "macro.dbt.get_show_sql": {"name": "get_show_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/show.sql", "original_file_path": "macros/adapters/show.sql", "unique_id": "macro.dbt.get_show_sql", "macro_sql": "{% macro get_show_sql(compiled_code, sql_header, limit) -%}\n  {%- if sql_header -%}\n  {{ sql_header }}\n  {%- endif -%}\n  {%- if limit is not none -%}\n  {{ get_limit_subquery_sql(compiled_code, limit) }}\n  {%- else -%}\n  {{ compiled_code }}\n  {%- endif -%}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_limit_subquery_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4211462, "supported_languages": null}, "macro.dbt.get_limit_subquery_sql": {"name": "get_limit_subquery_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/show.sql", "original_file_path": "macros/adapters/show.sql", "unique_id": "macro.dbt.get_limit_subquery_sql", "macro_sql": "{% macro get_limit_subquery_sql(sql, limit) %}\n  {{ adapter.dispatch('get_limit_subquery_sql', 'dbt')(sql, limit) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_limit_subquery_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.421351, "supported_languages": null}, "macro.dbt.default__get_limit_subquery_sql": {"name": "default__get_limit_subquery_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/show.sql", "original_file_path": "macros/adapters/show.sql", "unique_id": "macro.dbt.default__get_limit_subquery_sql", "macro_sql": "{% macro default__get_limit_subquery_sql(sql, limit) %}\n    select *\n    from (\n        {{ sql }}\n    ) as model_limit_subq\n    limit {{ limit }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.421504, "supported_languages": null}, "macro.dbt.alter_column_comment": {"name": "alter_column_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.alter_column_comment", "macro_sql": "{% macro alter_column_comment(relation, column_dict) -%}\n  {{ return(adapter.dispatch('alter_column_comment', 'dbt')(relation, column_dict)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_column_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.422226, "supported_languages": null}, "macro.dbt.default__alter_column_comment": {"name": "default__alter_column_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__alter_column_comment", "macro_sql": "{% macro default__alter_column_comment(relation, column_dict) -%}\n  {{ exceptions.raise_not_implemented(\n    'alter_column_comment macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.422389, "supported_languages": null}, "macro.dbt.alter_relation_comment": {"name": "alter_relation_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.alter_relation_comment", "macro_sql": "{% macro alter_relation_comment(relation, relation_comment) -%}\n  {{ return(adapter.dispatch('alter_relation_comment', 'dbt')(relation, relation_comment)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_relation_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4225862, "supported_languages": null}, "macro.dbt.default__alter_relation_comment": {"name": "default__alter_relation_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__alter_relation_comment", "macro_sql": "{% macro default__alter_relation_comment(relation, relation_comment) -%}\n  {{ exceptions.raise_not_implemented(\n    'alter_relation_comment macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.422762, "supported_languages": null}, "macro.dbt.persist_docs": {"name": "persist_docs", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.persist_docs", "macro_sql": "{% macro persist_docs(relation, model, for_relation=true, for_columns=true) -%}\n  {{ return(adapter.dispatch('persist_docs', 'dbt')(relation, model, for_relation, for_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__persist_docs"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.423021, "supported_languages": null}, "macro.dbt.default__persist_docs": {"name": "default__persist_docs", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/persist_docs.sql", "original_file_path": "macros/adapters/persist_docs.sql", "unique_id": "macro.dbt.default__persist_docs", "macro_sql": "{% macro default__persist_docs(relation, model, for_relation, for_columns) -%}\n  {% if for_relation and config.persist_relation_docs() and model.description %}\n    {% do run_query(alter_relation_comment(relation, model.description)) %}\n  {% endif %}\n\n  {% if for_columns and config.persist_column_docs() and model.columns %}\n    {% do run_query(alter_column_comment(relation, model.columns)) %}\n  {% endif %}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query", "macro.dbt.alter_relation_comment", "macro.dbt.alter_column_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4234922, "supported_languages": null}, "macro.dbt.get_catalog_relations": {"name": "get_catalog_relations", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.get_catalog_relations", "macro_sql": "{% macro get_catalog_relations(information_schema, relations) -%}\n  {{ return(adapter.dispatch('get_catalog_relations', 'dbt')(information_schema, relations)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_catalog_relations"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4262662, "supported_languages": null}, "macro.dbt.default__get_catalog_relations": {"name": "default__get_catalog_relations", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__get_catalog_relations", "macro_sql": "{% macro default__get_catalog_relations(information_schema, relations) -%}\n  {% set typename = adapter.type() %}\n  {% set msg -%}\n    get_catalog_relations not implemented for {{ typename }}\n  {%- endset %}\n\n  {{ exceptions.raise_compiler_error(msg) }}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.426522, "supported_languages": null}, "macro.dbt.get_catalog": {"name": "get_catalog", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.get_catalog", "macro_sql": "{% macro get_catalog(information_schema, schemas) -%}\n  {{ return(adapter.dispatch('get_catalog', 'dbt')(information_schema, schemas)) }}\n{%- endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_catalog"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.426711, "supported_languages": null}, "macro.dbt.default__get_catalog": {"name": "default__get_catalog", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__get_catalog", "macro_sql": "{% macro default__get_catalog(information_schema, schemas) -%}\n\n  {% set typename = adapter.type() %}\n  {% set msg -%}\n    get_catalog not implemented for {{ typename }}\n  {%- endset %}\n\n  {{ exceptions.raise_compiler_error(msg) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4269829, "supported_languages": null}, "macro.dbt.information_schema_name": {"name": "information_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.information_schema_name", "macro_sql": "{% macro information_schema_name(database) %}\n  {{ return(adapter.dispatch('information_schema_name', 'dbt')(database)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__information_schema_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.427163, "supported_languages": null}, "macro.dbt.default__information_schema_name": {"name": "default__information_schema_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__information_schema_name", "macro_sql": "{% macro default__information_schema_name(database) -%}\n  {%- if database -%}\n    {{ database }}.INFORMATION_SCHEMA\n  {%- else -%}\n    INFORMATION_SCHEMA\n  {%- endif -%}\n{%- endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.427315, "supported_languages": null}, "macro.dbt.list_schemas": {"name": "list_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.list_schemas", "macro_sql": "{% macro list_schemas(database) -%}\n  {{ return(adapter.dispatch('list_schemas', 'dbt')(database)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__list_schemas"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4274821, "supported_languages": null}, "macro.dbt.default__list_schemas": {"name": "default__list_schemas", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__list_schemas", "macro_sql": "{% macro default__list_schemas(database) -%}\n  {% set sql %}\n    select distinct schema_name\n    from {{ information_schema_name(database) }}.SCHEMATA\n    where catalog_name ilike '{{ database }}'\n  {% endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.information_schema_name", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.427791, "supported_languages": null}, "macro.dbt.check_schema_exists": {"name": "check_schema_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.check_schema_exists", "macro_sql": "{% macro check_schema_exists(information_schema, schema) -%}\n  {{ return(adapter.dispatch('check_schema_exists', 'dbt')(information_schema, schema)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__check_schema_exists"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.42798, "supported_languages": null}, "macro.dbt.default__check_schema_exists": {"name": "default__check_schema_exists", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__check_schema_exists", "macro_sql": "{% macro default__check_schema_exists(information_schema, schema) -%}\n  {% set sql -%}\n        select count(*)\n        from {{ information_schema.replace(information_schema_view='SCHEMATA') }}\n        where catalog_name='{{ information_schema.database }}'\n          and schema_name='{{ schema }}'\n  {%- endset %}\n  {{ return(run_query(sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.replace", "macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.428295, "supported_languages": null}, "macro.dbt.list_relations_without_caching": {"name": "list_relations_without_caching", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.list_relations_without_caching", "macro_sql": "{% macro list_relations_without_caching(schema_relation) %}\n  {{ return(adapter.dispatch('list_relations_without_caching', 'dbt')(schema_relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__list_relations_without_caching"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4284742, "supported_languages": null}, "macro.dbt.default__list_relations_without_caching": {"name": "default__list_relations_without_caching", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__list_relations_without_caching", "macro_sql": "{% macro default__list_relations_without_caching(schema_relation) %}\n  {{ exceptions.raise_not_implemented(\n    'list_relations_without_caching macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.428642, "supported_languages": null}, "macro.dbt.get_relations": {"name": "get_relations", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.get_relations", "macro_sql": "{% macro get_relations() %}\n  {{ return(adapter.dispatch('get_relations', 'dbt')()) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_relations"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4288142, "supported_languages": null}, "macro.dbt.default__get_relations": {"name": "default__get_relations", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__get_relations", "macro_sql": "{% macro default__get_relations() %}\n  {{ exceptions.raise_not_implemented(\n    'get_relations macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.428958, "supported_languages": null}, "macro.dbt.get_relation_last_modified": {"name": "get_relation_last_modified", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.get_relation_last_modified", "macro_sql": "{% macro get_relation_last_modified(information_schema, relations) %}\n  {{ return(adapter.dispatch('get_relation_last_modified', 'dbt')(information_schema, relations)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_relation_last_modified"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4291542, "supported_languages": null}, "macro.dbt.default__get_relation_last_modified": {"name": "default__get_relation_last_modified", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/metadata.sql", "original_file_path": "macros/adapters/metadata.sql", "unique_id": "macro.dbt.default__get_relation_last_modified", "macro_sql": "{% macro default__get_relation_last_modified(information_schema, relations) %}\n  {{ exceptions.raise_not_implemented(\n    'get_relation_last_modified macro not implemented for adapter ' + adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.429329, "supported_languages": null}, "macro.dbt.get_columns_in_relation": {"name": "get_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_columns_in_relation", "macro_sql": "{% macro get_columns_in_relation(relation) -%}\n  {{ return(adapter.dispatch('get_columns_in_relation', 'dbt')(relation)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__get_columns_in_relation"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4315882, "supported_languages": null}, "macro.dbt.default__get_columns_in_relation": {"name": "default__get_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_columns_in_relation", "macro_sql": "{% macro default__get_columns_in_relation(relation) -%}\n  {{ exceptions.raise_not_implemented(\n    'get_columns_in_relation macro not implemented for adapter '+adapter.type()) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.431743, "supported_languages": null}, "macro.dbt.sql_convert_columns_in_relation": {"name": "sql_convert_columns_in_relation", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.sql_convert_columns_in_relation", "macro_sql": "{% macro sql_convert_columns_in_relation(table) -%}\n  {% set columns = [] %}\n  {% for row in table %}\n    {% do columns.append(api.Column(*row)) %}\n  {% endfor %}\n  {{ return(columns) }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.432042, "supported_languages": null}, "macro.dbt.get_empty_subquery_sql": {"name": "get_empty_subquery_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_empty_subquery_sql", "macro_sql": "{% macro get_empty_subquery_sql(select_sql, select_sql_header=none) -%}\n  {{ return(adapter.dispatch('get_empty_subquery_sql', 'dbt')(select_sql, select_sql_header)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_empty_subquery_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4322581, "supported_languages": null}, "macro.dbt.default__get_empty_subquery_sql": {"name": "default__get_empty_subquery_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_empty_subquery_sql", "macro_sql": "{% macro default__get_empty_subquery_sql(select_sql, select_sql_header=none) %}\n    {%- if select_sql_header is not none -%}\n    {{ select_sql_header }}\n    {%- endif -%}\n    select * from (\n        {{ select_sql }}\n    ) as __dbt_sbq\n    where false\n    limit 0\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.432459, "supported_languages": null}, "macro.dbt.get_empty_schema_sql": {"name": "get_empty_schema_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_empty_schema_sql", "macro_sql": "{% macro get_empty_schema_sql(columns) -%}\n  {{ return(adapter.dispatch('get_empty_schema_sql', 'dbt')(columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_empty_schema_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.432628, "supported_languages": null}, "macro.dbt.default__get_empty_schema_sql": {"name": "default__get_empty_schema_sql", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_empty_schema_sql", "macro_sql": "{% macro default__get_empty_schema_sql(columns) %}\n    {%- set col_err = [] -%}\n    {%- set col_naked_numeric = [] -%}\n    select\n    {% for i in columns %}\n      {%- set col = columns[i] -%}\n      {%- if col['data_type'] is not defined -%}\n        {%- do col_err.append(col['name']) -%}\n      {#-- If this column's type is just 'numeric' then it is missing precision/scale, raise a warning --#}\n      {%- elif col['data_type'].strip().lower() in ('numeric', 'decimal', 'number') -%}\n        {%- do col_naked_numeric.append(col['name']) -%}\n      {%- endif -%}\n      {% set col_name = adapter.quote(col['name']) if col.get('quote') else col['name'] %}\n      cast(null as {{ col['data_type'] }}) as {{ col_name }}{{ \", \" if not loop.last }}\n    {%- endfor -%}\n    {%- if (col_err | length) > 0 -%}\n      {{ exceptions.column_type_missing(column_names=col_err) }}\n    {%- elif (col_naked_numeric | length) > 0 -%}\n      {{ exceptions.warn(\"Detected columns with numeric type and unspecified precision/scale, this can lead to unintended rounding: \" ~ col_naked_numeric ~ \"`\") }}\n    {%- endif -%}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4338, "supported_languages": null}, "macro.dbt.get_column_schema_from_query": {"name": "get_column_schema_from_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_column_schema_from_query", "macro_sql": "{% macro get_column_schema_from_query(select_sql, select_sql_header=none) -%}\n    {% set columns = [] %}\n    {# -- Using an 'empty subquery' here to get the same schema as the given select_sql statement, without necessitating a data scan.#}\n    {% set sql = get_empty_subquery_sql(select_sql, select_sql_header) %}\n    {% set column_schema = adapter.get_column_schema_from_query(sql) %}\n    {{ return(column_schema) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.get_empty_subquery_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.434129, "supported_languages": null}, "macro.dbt.get_columns_in_query": {"name": "get_columns_in_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.get_columns_in_query", "macro_sql": "{% macro get_columns_in_query(select_sql) -%}\n  {{ return(adapter.dispatch('get_columns_in_query', 'dbt')(select_sql)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__get_columns_in_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.434307, "supported_languages": null}, "macro.dbt.default__get_columns_in_query": {"name": "default__get_columns_in_query", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__get_columns_in_query", "macro_sql": "{% macro default__get_columns_in_query(select_sql) %}\n    {% call statement('get_columns_in_query', fetch_result=True, auto_begin=False) -%}\n        {{ get_empty_subquery_sql(select_sql) }}\n    {% endcall %}\n    {{ return(load_result('get_columns_in_query').table.columns | map(attribute='name') | list) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement", "macro.dbt.get_empty_subquery_sql"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4346728, "supported_languages": null}, "macro.dbt.alter_column_type": {"name": "alter_column_type", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.alter_column_type", "macro_sql": "{% macro alter_column_type(relation, column_name, new_column_type) -%}\n  {{ return(adapter.dispatch('alter_column_type', 'dbt')(relation, column_name, new_column_type)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__alter_column_type"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.434895, "supported_languages": null}, "macro.dbt.default__alter_column_type": {"name": "default__alter_column_type", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__alter_column_type", "macro_sql": "{% macro default__alter_column_type(relation, column_name, new_column_type) -%}\n  {#\n    1. Create a new column (w/ temp name and correct type)\n    2. Copy data over to it\n    3. Drop the existing column (cascade!)\n    4. Rename the new column to existing column\n  #}\n  {%- set tmp_column = column_name + \"__dbt_alter\" -%}\n\n  {% call statement('alter_column_type') %}\n    alter table {{ relation }} add column {{ adapter.quote(tmp_column) }} {{ new_column_type }};\n    update {{ relation }} set {{ adapter.quote(tmp_column) }} = {{ adapter.quote(column_name) }};\n    alter table {{ relation }} drop column {{ adapter.quote(column_name) }} cascade;\n    alter table {{ relation }} rename column {{ adapter.quote(tmp_column) }} to {{ adapter.quote(column_name) }}\n  {% endcall %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.statement"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.43546, "supported_languages": null}, "macro.dbt.alter_relation_add_remove_columns": {"name": "alter_relation_add_remove_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.alter_relation_add_remove_columns", "macro_sql": "{% macro alter_relation_add_remove_columns(relation, add_columns = none, remove_columns = none) -%}\n  {{ return(adapter.dispatch('alter_relation_add_remove_columns', 'dbt')(relation, add_columns, remove_columns)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt_duckdb.duckdb__alter_relation_add_remove_columns"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.435704, "supported_languages": null}, "macro.dbt.default__alter_relation_add_remove_columns": {"name": "default__alter_relation_add_remove_columns", "resource_type": "macro", "package_name": "dbt", "path": "macros/adapters/columns.sql", "original_file_path": "macros/adapters/columns.sql", "unique_id": "macro.dbt.default__alter_relation_add_remove_columns", "macro_sql": "{% macro default__alter_relation_add_remove_columns(relation, add_columns, remove_columns) %}\n\n  {% if add_columns is none %}\n    {% set add_columns = [] %}\n  {% endif %}\n  {% if remove_columns is none %}\n    {% set remove_columns = [] %}\n  {% endif %}\n\n  {% set sql -%}\n\n     alter {{ relation.type }} {{ relation }}\n\n            {% for column in add_columns %}\n               add column {{ column.name }} {{ column.data_type }}{{ ',' if not loop.last }}\n            {% endfor %}{{ ',' if add_columns and remove_columns }}\n\n            {% for column in remove_columns %}\n                drop column {{ column.name }}{{ ',' if not loop.last }}\n            {% endfor %}\n\n  {%- endset -%}\n\n  {% do run_query(sql) %}\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.run_query"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.436485, "supported_languages": null}, "macro.dbt.resolve_model_name": {"name": "resolve_model_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.resolve_model_name", "macro_sql": "{% macro resolve_model_name(input_model_name) %}\n    {{ return(adapter.dispatch('resolve_model_name', 'dbt')(input_model_name)) }}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.default__resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.438126, "supported_languages": null}, "macro.dbt.default__resolve_model_name": {"name": "default__resolve_model_name", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.default__resolve_model_name", "macro_sql": "\n\n{%- macro default__resolve_model_name(input_model_name) -%}\n    {{  input_model_name | string | replace('\"', '\\\"') }}\n{%- endmacro -%}\n\n", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.438272, "supported_languages": null}, "macro.dbt.build_ref_function": {"name": "build_ref_function", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_ref_function", "macro_sql": "{% macro build_ref_function(model) %}\n\n    {%- set ref_dict = {} -%}\n    {%- for _ref in model.refs -%}\n        {% set _ref_args = [_ref.get('package'), _ref['name']] if _ref.get('package') else [_ref['name'],] %}\n        {%- set resolved = ref(*_ref_args, v=_ref.get('version')) -%}\n        {%- if _ref.get('version') -%}\n            {% do _ref_args.extend([\"v\" ~ _ref['version']]) %}\n        {%- endif -%}\n       {%- do ref_dict.update({_ref_args | join('.'): resolve_model_name(resolved)}) -%}\n    {%- endfor -%}\n\ndef ref(*args, **kwargs):\n    refs = {{ ref_dict | tojson }}\n    key = '.'.join(args)\n    version = kwargs.get(\"v\") or kwargs.get(\"version\")\n    if version:\n        key += f\".v{version}\"\n    dbt_load_df_function = kwargs.get(\"dbt_load_df_function\")\n    return dbt_load_df_function(refs[key])\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.439056, "supported_languages": null}, "macro.dbt.build_source_function": {"name": "build_source_function", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_source_function", "macro_sql": "{% macro build_source_function(model) %}\n\n    {%- set source_dict = {} -%}\n    {%- for _source in model.sources -%}\n        {%- set resolved = source(*_source) -%}\n        {%- do source_dict.update({_source | join('.'): resolve_model_name(resolved)}) -%}\n    {%- endfor -%}\n\ndef source(*args, dbt_load_df_function):\n    sources = {{ source_dict | tojson }}\n    key = '.'.join(args)\n    return dbt_load_df_function(sources[key])\n\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.resolve_model_name"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.439469, "supported_languages": null}, "macro.dbt.build_config_dict": {"name": "build_config_dict", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.build_config_dict", "macro_sql": "{% macro build_config_dict(model) %}\n    {%- set config_dict = {} -%}\n    {% set config_dbt_used = zip(model.config.config_keys_used, model.config.config_keys_defaults) | list %}\n    {%- for key, default in config_dbt_used -%}\n        {# weird type testing with enum, would be much easier to write this logic in Python! #}\n        {%- if key == \"language\" -%}\n          {%- set value = \"python\" -%}\n        {%- endif -%}\n        {%- set value = model.config.get(key, default) -%}\n        {%- do config_dict.update({key: value}) -%}\n    {%- endfor -%}\nconfig_dict = {{ config_dict }}\n{% endmacro %}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.440036, "supported_languages": null}, "macro.dbt.py_script_postfix": {"name": "py_script_postfix", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.py_script_postfix", "macro_sql": "{% macro py_script_postfix(model) %}\n# This part is user provided model code\n# you will need to copy the next section to run the code\n# COMMAND ----------\n# this part is dbt logic for get ref work, do not modify\n\n{{ build_ref_function(model ) }}\n{{ build_source_function(model ) }}\n{{ build_config_dict(model) }}\n\nclass config:\n    def __init__(self, *args, **kwargs):\n        pass\n\n    @staticmethod\n    def get(key, default=None):\n        return config_dict.get(key, default)\n\nclass this:\n    \"\"\"dbt.this() or dbt.this.identifier\"\"\"\n    database = \"{{ this.database }}\"\n    schema = \"{{ this.schema }}\"\n    identifier = \"{{ this.identifier }}\"\n    {% set this_relation_name = resolve_model_name(this) %}\n    def __repr__(self):\n        return '{{ this_relation_name  }}'\n\n\nclass dbtObj:\n    def __init__(self, load_df_function) -> None:\n        self.source = lambda *args: source(*args, dbt_load_df_function=load_df_function)\n        self.ref = lambda *args, **kwargs: ref(*args, **kwargs, dbt_load_df_function=load_df_function)\n        self.config = config\n        self.this = this()\n        self.is_incremental = {{ is_incremental() }}\n\n# COMMAND ----------\n{{py_script_comment()}}\n{% endmacro %}", "depends_on": {"macros": ["macro.dbt.build_ref_function", "macro.dbt.build_source_function", "macro.dbt.build_config_dict", "macro.dbt.resolve_model_name", "macro.dbt.is_incremental", "macro.dbt.py_script_comment"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.440507, "supported_languages": null}, "macro.dbt.py_script_comment": {"name": "py_script_comment", "resource_type": "macro", "package_name": "dbt", "path": "macros/python_model/python.sql", "original_file_path": "macros/python_model/python.sql", "unique_id": "macro.dbt.py_script_comment", "macro_sql": "{%macro py_script_comment()%}\n{%endmacro%}", "depends_on": {"macros": []}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.440581, "supported_languages": null}, "macro.dbt.test_unique": {"name": "test_unique", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_unique", "macro_sql": "{% test unique(model, column_name) %}\n    {% set macro = adapter.dispatch('test_unique', 'dbt') %}\n    {{ macro(model, column_name) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_unique"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4410932, "supported_languages": null}, "macro.dbt.test_not_null": {"name": "test_not_null", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_not_null", "macro_sql": "{% test not_null(model, column_name) %}\n    {% set macro = adapter.dispatch('test_not_null', 'dbt') %}\n    {{ macro(model, column_name) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_not_null"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.441312, "supported_languages": null}, "macro.dbt.test_accepted_values": {"name": "test_accepted_values", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_accepted_values", "macro_sql": "{% test accepted_values(model, column_name, values, quote=True) %}\n    {% set macro = adapter.dispatch('test_accepted_values', 'dbt') %}\n    {{ macro(model, column_name, values, quote) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_accepted_values"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.4416041, "supported_languages": null}, "macro.dbt.test_relationships": {"name": "test_relationships", "resource_type": "macro", "package_name": "dbt", "path": "tests/generic/builtin.sql", "original_file_path": "tests/generic/builtin.sql", "unique_id": "macro.dbt.test_relationships", "macro_sql": "{% test relationships(model, column_name, to, field) %}\n    {% set macro = adapter.dispatch('test_relationships', 'dbt') %}\n    {{ macro(model, column_name, to, field) }}\n{% endtest %}", "depends_on": {"macros": ["macro.dbt.default__test_relationships"]}, "description": "", "meta": {}, "docs": {"show": true, "node_color": null}, "patch_path": null, "arguments": [], "created_at": 1706724325.441893, "supported_languages": null}}, "docs": {"doc.datafold_demo.__overview__": {"name": "__overview__", "resource_type": "doc", "package_name": "datafold_demo", "path": "overview.md", "original_file_path": "models/overview.md", "unique_id": "doc.datafold_demo.__overview__", "block_contents": "## Data Documentation for Jaffle Shop\n\n`jaffle_shop` is a fictional ecommerce store.\n\nThis [dbt](https://www.getdbt.com/) project is for testing out code.\n\nThe source code can be found [here](https://github.com/clrcrl/jaffle_shop)."}, "doc.datafold_demo.orders_status": {"name": "orders_status", "resource_type": "doc", "package_name": "datafold_demo", "path": "docs.md", "original_file_path": "models/docs.md", "unique_id": "doc.datafold_demo.orders_status", "block_contents": "Orders can be one of the following statuses:\n\n| status         | description                                                                                                            |\n|----------------|------------------------------------------------------------------------------------------------------------------------|\n| placed         | The order has been placed but has not yet left the warehouse                                                           |\n| shipped        | The order has ben shipped to the customer and is currently in transit                                                  |\n| completed      | The order has been received by the customer                                                                            |\n| return_pending | The customer has indicated that they would like to return the order, but it has not yet been received at the warehouse |\n| returned       | The order has been returned by the customer and received at the warehouse                                              |"}, "doc.dbt.__overview__": {"name": "__overview__", "resource_type": "doc", "package_name": "dbt", "path": "overview.md", "original_file_path": "docs/overview.md", "unique_id": "doc.dbt.__overview__", "block_contents": "### Welcome!\n\nWelcome to the auto-generated documentation for your dbt project!\n\n### Navigation\n\nYou can use the `Project` and `Database` navigation tabs on the left side of the window to explore the models\nin your project.\n\n#### Project Tab\nThe `Project` tab mirrors the directory structure of your dbt project. In this tab, you can see all of the\nmodels defined in your dbt project, as well as models imported from dbt packages.\n\n#### Database Tab\nThe `Database` tab also exposes your models, but in a format that looks more like a database explorer. This view\nshows relations (tables and views) grouped into database schemas. Note that ephemeral models are _not_ shown\nin this interface, as they do not exist in the database.\n\n### Graph Exploration\nYou can click the blue icon on the bottom-right corner of the page to view the lineage graph of your models.\n\nOn model pages, you'll see the immediate parents and children of the model you're exploring. By clicking the `Expand`\nbutton at the top-right of this lineage pane, you'll be able to see all of the models that are used to build,\nor are built from, the model you're exploring.\n\nOnce expanded, you'll be able to use the `--select` and `--exclude` model selection syntax to filter the\nmodels in the graph. For more information on model selection, check out the [dbt docs](https://docs.getdbt.com/docs/model-selection-syntax).\n\nNote that you can also right-click on models to interactively filter and explore the graph.\n\n---\n\n### More information\n\n- [What is dbt](https://docs.getdbt.com/docs/introduction)?\n- Read the [dbt viewpoint](https://docs.getdbt.com/docs/viewpoint)\n- [Installation](https://docs.getdbt.com/docs/installation)\n- Join the [dbt Community](https://www.getdbt.com/community/) for questions and discussion"}}, "exposures": {}, "metrics": {}, "groups": {}, "selectors": {}, "disabled": {}, "parent_map": {"model.datafold_demo.stg_customers": ["seed.datafold_demo.raw_customers"], "model.datafold_demo.stg_payments": ["seed.datafold_demo.raw_payments"], "model.datafold_demo.stg_orders": ["seed.datafold_demo.raw_orders"], "model.datafold_demo.customers": ["model.datafold_demo.stg_customers", "model.datafold_demo.stg_orders", "model.datafold_demo.stg_payments"], "model.datafold_demo.orders": ["model.datafold_demo.stg_orders", "model.datafold_demo.stg_payments"], "seed.datafold_demo.raw_customers": [], "seed.datafold_demo.raw_orders": [], "seed.datafold_demo.raw_payments": [], "test.datafold_demo.unique_stg_customers_customer_id.c7614daada": ["model.datafold_demo.stg_customers"], "test.datafold_demo.not_null_stg_customers_customer_id.e2cfb1f9aa": ["model.datafold_demo.stg_customers"], "test.datafold_demo.unique_stg_orders_order_id.e3b841c71a": ["model.datafold_demo.stg_orders"], "test.datafold_demo.not_null_stg_orders_order_id.81cfe2fe64": ["model.datafold_demo.stg_orders"], "test.datafold_demo.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": ["model.datafold_demo.stg_orders"], "test.datafold_demo.unique_stg_payments_payment_id.3744510712": ["model.datafold_demo.stg_payments"], "test.datafold_demo.not_null_stg_payments_payment_id.c19cc50075": ["model.datafold_demo.stg_payments"], "test.datafold_demo.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": ["model.datafold_demo.stg_payments"], "test.datafold_demo.unique_customers_customer_id.c5af1ff4b1": ["model.datafold_demo.customers"], "test.datafold_demo.not_null_customers_customer_id.5c9bf9911d": ["model.datafold_demo.customers"], "test.datafold_demo.unique_orders_order_id.fed79b3a6e": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_order_id.cf6c17daed": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_customer_id.c5f02694af": ["model.datafold_demo.orders"], "test.datafold_demo.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_amount.106140f9fd": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_credit_card_amount.d3ca593b59": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_coupon_amount.ab90c90625": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_bank_transfer_amount.7743500c49": ["model.datafold_demo.orders"], "test.datafold_demo.not_null_orders_gift_card_amount.413a0d2d7a": ["model.datafold_demo.orders"]}, "child_map": {"model.datafold_demo.stg_customers": ["model.datafold_demo.customers", "test.datafold_demo.not_null_stg_customers_customer_id.e2cfb1f9aa", "test.datafold_demo.unique_stg_customers_customer_id.c7614daada"], "model.datafold_demo.stg_payments": ["model.datafold_demo.customers", "model.datafold_demo.orders", "test.datafold_demo.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278", "test.datafold_demo.not_null_stg_payments_payment_id.c19cc50075", "test.datafold_demo.unique_stg_payments_payment_id.3744510712"], "model.datafold_demo.stg_orders": ["model.datafold_demo.customers", "model.datafold_demo.orders", "test.datafold_demo.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad", "test.datafold_demo.not_null_stg_orders_order_id.81cfe2fe64", "test.datafold_demo.unique_stg_orders_order_id.e3b841c71a"], "model.datafold_demo.customers": ["test.datafold_demo.not_null_customers_customer_id.5c9bf9911d", "test.datafold_demo.unique_customers_customer_id.c5af1ff4b1"], "model.datafold_demo.orders": ["test.datafold_demo.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3", "test.datafold_demo.not_null_orders_amount.106140f9fd", "test.datafold_demo.not_null_orders_bank_transfer_amount.7743500c49", "test.datafold_demo.not_null_orders_coupon_amount.ab90c90625", "test.datafold_demo.not_null_orders_credit_card_amount.d3ca593b59", "test.datafold_demo.not_null_orders_customer_id.c5f02694af", "test.datafold_demo.not_null_orders_gift_card_amount.413a0d2d7a", "test.datafold_demo.not_null_orders_order_id.cf6c17daed", "test.datafold_demo.unique_orders_order_id.fed79b3a6e"], "seed.datafold_demo.raw_customers": ["model.datafold_demo.stg_customers"], "seed.datafold_demo.raw_orders": ["model.datafold_demo.stg_orders"], "seed.datafold_demo.raw_payments": ["model.datafold_demo.stg_payments"], "test.datafold_demo.unique_stg_customers_customer_id.c7614daada": [], "test.datafold_demo.not_null_stg_customers_customer_id.e2cfb1f9aa": [], "test.datafold_demo.unique_stg_orders_order_id.e3b841c71a": [], "test.datafold_demo.not_null_stg_orders_order_id.81cfe2fe64": [], "test.datafold_demo.accepted_values_stg_orders_status__placed__shipped__completed__return_pending__returned.080fb20aad": [], "test.datafold_demo.unique_stg_payments_payment_id.3744510712": [], "test.datafold_demo.not_null_stg_payments_payment_id.c19cc50075": [], "test.datafold_demo.accepted_values_stg_payments_payment_method__credit_card__coupon__bank_transfer__gift_card.3c3820f278": [], "test.datafold_demo.unique_customers_customer_id.c5af1ff4b1": [], "test.datafold_demo.not_null_customers_customer_id.5c9bf9911d": [], "test.datafold_demo.unique_orders_order_id.fed79b3a6e": [], "test.datafold_demo.not_null_orders_order_id.cf6c17daed": [], "test.datafold_demo.not_null_orders_customer_id.c5f02694af": [], "test.datafold_demo.accepted_values_orders_status__placed__shipped__completed__return_pending__returned.be6b5b5ec3": [], "test.datafold_demo.not_null_orders_amount.106140f9fd": [], "test.datafold_demo.not_null_orders_credit_card_amount.d3ca593b59": [], "test.datafold_demo.not_null_orders_coupon_amount.ab90c90625": [], "test.datafold_demo.not_null_orders_bank_transfer_amount.7743500c49": [], "test.datafold_demo.not_null_orders_gift_card_amount.413a0d2d7a": []}, "group_map": {}, "saved_queries": {}, "semantic_models": {}}
\ No newline at end of file
diff --git a/tests/dbt_artifacts/target/run_results.json b/tests/dbt_artifacts/target/run_results.json
index 6886685e0..69fff250d 100644
--- a/tests/dbt_artifacts/target/run_results.json
+++ b/tests/dbt_artifacts/target/run_results.json
@@ -1 +1 @@
-{"metadata": {"dbt_schema_version": "https://schemas.getdbt.com/dbt/run-results/v4.json", "dbt_version": "1.4.5", "generated_at": "2023-03-28T17:53:00.424212Z", "invocation_id": "289d7789-15b8-44be-a1f6-828f34858212", "env": {}}, "results": [{"status": "success", "timing": [{"name": "compile", "started_at": "2023-03-28T17:53:00.283978Z", "completed_at": "2023-03-28T17:53:00.285641Z"}, {"name": "execute", "started_at": "2023-03-28T17:53:00.285856Z", "completed_at": "2023-03-28T17:53:00.341543Z"}], "thread_id": "Thread-1 (worker)", "execution_time": 0.059603214263916016, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.jaffle_shop.stg_customers"}, {"status": "success", "timing": [{"name": "compile", "started_at": "2023-03-28T17:53:00.345114Z", "completed_at": "2023-03-28T17:53:00.346354Z"}, {"name": "execute", "started_at": "2023-03-28T17:53:00.346549Z", "completed_at": "2023-03-28T17:53:00.357085Z"}], "thread_id": "Thread-1 (worker)", "execution_time": 0.013532876968383789, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.jaffle_shop.stg_orders"}, {"status": "success", "timing": [{"name": "compile", "started_at": "2023-03-28T17:53:00.359417Z", "completed_at": "2023-03-28T17:53:00.360809Z"}, {"name": "execute", "started_at": "2023-03-28T17:53:00.361018Z", "completed_at": "2023-03-28T17:53:00.371547Z"}], "thread_id": "Thread-1 (worker)", "execution_time": 0.013769149780273438, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.jaffle_shop.stg_payments"}, {"status": "success", "timing": [{"name": "compile", "started_at": "2023-03-28T17:53:00.374177Z", "completed_at": "2023-03-28T17:53:00.375799Z"}, {"name": "execute", "started_at": "2023-03-28T17:53:00.376001Z", "completed_at": "2023-03-28T17:53:00.399869Z"}], "thread_id": "Thread-1 (worker)", "execution_time": 0.02851414680480957, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.jaffle_shop.customers"}, {"status": "success", "timing": [{"name": "compile", "started_at": "2023-03-28T17:53:00.403579Z", "completed_at": "2023-03-28T17:53:00.405505Z"}, {"name": "execute", "started_at": "2023-03-28T17:53:00.405703Z", "completed_at": "2023-03-28T17:53:00.417432Z"}], "thread_id": "Thread-1 (worker)", "execution_time": 0.01594710350036621, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.jaffle_shop.orders"}], "elapsed_time": 0.17573904991149902, "args": {"write_json": true, "use_colors": true, "printer_width": 80, "version_check": true, "partial_parse": true, "static_parser": true, "profiles_dir": "/Users/dan/.dbt", "send_anonymous_usage_stats": true, "quiet": false, "no_print": false, "cache_selected_only": false, "target": "dev", "which": "run", "rpc_method": "run", "indirect_selection": "eager"}}
\ No newline at end of file
+{"metadata": {"dbt_schema_version": "https://schemas.getdbt.com/dbt/run-results/v5.json", "dbt_version": "1.7.3", "generated_at": "2024-01-31T18:05:26.126216Z", "invocation_id": "baf0db27-f48e-40a3-aa05-1b05b809ec5a", "env": {}}, "results": [{"status": "success", "timing": [{"name": "compile", "started_at": "2024-01-31T18:05:25.960740Z", "completed_at": "2024-01-31T18:05:25.969466Z"}, {"name": "execute", "started_at": "2024-01-31T18:05:25.970040Z", "completed_at": "2024-01-31T18:05:26.040906Z"}], "thread_id": "Thread-1", "execution_time": 0.08749794960021973, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.datafold_demo.stg_customers", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_customers\"\n\n),\n\nrenamed as (\n\n    select\n        id as customer_id,\n        first_name,\n        last_name\n\n    from source\n\n)\n\nselect * from renamed", "relation_name": "\"jaffle_shop\".\"dev\".\"stg_customers\""}, {"status": "success", "timing": [{"name": "compile", "started_at": "2024-01-31T18:05:25.967740Z", "completed_at": "2024-01-31T18:05:25.982895Z"}, {"name": "execute", "started_at": "2024-01-31T18:05:25.993495Z", "completed_at": "2024-01-31T18:05:26.048436Z"}], "thread_id": "Thread-3", "execution_time": 0.09017610549926758, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.datafold_demo.stg_payments", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_payments\"\n\n),\n\nrenamed as (\n\n    select\n        id as payment_id,\n        order_id,\n        payment_method,\n\n        -- `amount` is currently stored in cents, so we convert it to dollars\n        amount / 100 as amount\n\n    from source\n\n)\n\nselect * from renamed", "relation_name": "\"jaffle_shop\".\"dev\".\"stg_payments\""}, {"status": "success", "timing": [{"name": "compile", "started_at": "2024-01-31T18:05:25.965435Z", "completed_at": "2024-01-31T18:05:25.976208Z"}, {"name": "execute", "started_at": "2024-01-31T18:05:25.990582Z", "completed_at": "2024-01-31T18:05:26.049746Z"}], "thread_id": "Thread-2", "execution_time": 0.09407401084899902, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.datafold_demo.stg_orders", "compiled": true, "compiled_code": "with source as (\n    select * from \"jaffle_shop\".\"dev\".\"raw_orders\"\n\n),\n\nrenamed as (\n\n    select\n        id as order_id,\n        user_id as customer_id,\n        order_date,\n        status\n\n    from source\n\n)\n\nselect * from renamed", "relation_name": "\"jaffle_shop\".\"dev\".\"stg_orders\""}, {"status": "success", "timing": [{"name": "compile", "started_at": "2024-01-31T18:05:26.057925Z", "completed_at": "2024-01-31T18:05:26.062891Z"}, {"name": "execute", "started_at": "2024-01-31T18:05:26.064062Z", "completed_at": "2024-01-31T18:05:26.110534Z"}], "thread_id": "Thread-5", "execution_time": 0.05589699745178223, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.datafold_demo.customers", "compiled": true, "compiled_code": "with customers as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_customers\"\n\n),\n\norders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\ncustomer_orders as (\n\n        select\n        customer_id,\n\n        min(order_date) as first_order,\n        max(order_date) as most_recent_order,\n        count(order_id) as number_of_orders\n    from orders\n\n    group by customer_id\n\n),\n\ncustomer_payments as (\n\n    select\n        orders.customer_id,\n        sum(amount) as total_amount\n\n    from payments\n\n    left join orders on\n         payments.order_id = orders.order_id\n\n    group by orders.customer_id\n\n),\n\nfinal as (\n\n    select\n        customers.customer_id,\n        customers.first_name,\n        customers.last_name,\n        customer_orders.first_order,\n        customer_orders.most_recent_order,\n        customer_orders.number_of_orders,\n        customer_payments.total_amount as customer_lifetime_value\n\n    from customers\n\n    left join customer_orders\n        on customers.customer_id = customer_orders.customer_id\n\n    left join customer_payments\n        on  customers.customer_id = customer_payments.customer_id\n\n)\n\nselect * from final", "relation_name": "\"jaffle_shop\".\"dev\".\"customers\""}, {"status": "success", "timing": [{"name": "compile", "started_at": "2024-01-31T18:05:26.059981Z", "completed_at": "2024-01-31T18:05:26.063227Z"}, {"name": "execute", "started_at": "2024-01-31T18:05:26.075887Z", "completed_at": "2024-01-31T18:05:26.111336Z"}], "thread_id": "Thread-6", "execution_time": 0.0593719482421875, "adapter_response": {"_message": "OK"}, "message": "OK", "failures": null, "unique_id": "model.datafold_demo.orders", "compiled": true, "compiled_code": "\n\nwith orders as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_orders\"\n\n),\n\npayments as (\n\n    select * from \"jaffle_shop\".\"dev\".\"stg_payments\"\n\n),\n\norder_payments as (\n\n    select\n        order_id,\n\n        sum(case when payment_method = 'credit_card' then amount else 0 end) as credit_card_amount,\n        sum(case when payment_method = 'coupon' then amount else 0 end) as coupon_amount,\n        sum(case when payment_method = 'bank_transfer' then amount else 0 end) as bank_transfer_amount,\n        sum(case when payment_method = 'gift_card' then amount else 0 end) as gift_card_amount,\n        sum(amount) as total_amount\n\n    from payments\n\n    group by order_id\n\n),\n\nfinal as (\n\n    select\n        orders.order_id+1 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        \n        1 as new_column,\n\n        order_payments.credit_card_amount,\n\n        order_payments.coupon_amount,\n\n        order_payments.bank_transfer_amount,\n\n        order_payments.gift_card_amount,\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n),\n\nfinal2 as (\n\n    select\n        orders.order_id+2 as order_id,\n        orders.customer_id,\n        cast(orders.order_date as varchar) as order_date,\n        \n        1 as new_column,\n\n        order_payments.credit_card_amount,\n\n        order_payments.coupon_amount,\n\n        order_payments.bank_transfer_amount,\n\n        order_payments.gift_card_amount,\n\n        order_payments.total_amount as amount\n\n    from orders\n\n\n    left join order_payments\n        on orders.order_id = order_payments.order_id\n\n)\n\n(select * from final limit 10)\nunion all\n(select * from final2 where order_id not in (select order_id from final) limit 10)", "relation_name": "\"jaffle_shop\".\"dev\".\"orders\""}], "elapsed_time": 0.23143315315246582, "args": {"log_path": "/Users/sung/Desktop/data-diff/data_diff_demo/logs", "strict_mode": false, "macro_debugging": false, "log_file_max_bytes": 10485760, "warn_error_options": {"include": [], "exclude": []}, "send_anonymous_usage_stats": true, "partial_parse": true, "defer": false, "log_level": "info", "enable_legacy_logger": false, "use_colors_file": true, "cache_selected_only": false, "version_check": true, "vars": {}, "log_level_file": "debug", "exclude": [], "populate_cache": true, "quiet": false, "profiles_dir": "/Users/sung/Desktop/data-diff/data_diff_demo", "which": "run", "favor_state": false, "partial_parse_file_diff": true, "invocation_command": "dbt run", "log_format_file": "debug", "use_colors": true, "indirect_selection": "eager", "project_dir": "/Users/sung/Desktop/data-diff/data_diff_demo", "introspect": true, "select": [], "write_json": true, "printer_width": 80, "show_resource_report": false, "print": true, "log_format": "default", "static_parser": true}}
\ No newline at end of file
diff --git a/tests/test_dbt.py b/tests/test_dbt.py
index 74faba70b..764f8d179 100644
--- a/tests/test_dbt.py
+++ b/tests/test_dbt.py
@@ -36,15 +36,75 @@ def test_integration_basic_dbt(self):
             "--dbt", "--dbt-project-dir", test_project_path, "--dbt-profiles-dir", test_profiles_path
         )
 
-        # assertions for the diff that exists in tests/dbt_artifacts/jaffle_shop.duckdb
+        orders_expected_output = """
+        jaffle_shop.prod.orders <> jaffle_shop.dev.orders 
+        Primary Keys: ['order_id'] 
+        Where Filter: 'amount >= 0' 
+        Included Columns: ['order_id', 'customer_id', 'order_date', 'amount', 'credit_card_amount', 'coupon_amount', 
+        'bank_transfer_amount', 'gift_card_amount'] 
+        Excluded Columns: ['new_column'] 
+        Columns removed [-1]: {'status'}
+        Columns added [+1]: {'new_column'}
+        Type changed [1]: {'order_date'}
+
+        rows       PROD    <>            DEV
+        ---------  ------  ------------  -----------------
+        Total      10                    11 [+1]
+        Added              +2
+        Removed            -1
+        Different          9
+        Unchanged          0
+
+        columns                 # diff values
+        --------------------  ---------------
+        amount                              8
+        bank_transfer_amount                3
+        coupon_amount                       3
+        credit_card_amount                  6
+        customer_id                         9
+        gift_card_amount                    2 
+        """
+
+        stg_payments_expected_output = """
+        jaffle_shop.prod.stg_payments <> jaffle_shop.dev.stg_payments 
+        Primary Keys: ['payment_id'] 
+        No row differences
+        """
+
+        stg_customers_expected_output = """
+        jaffle_shop.prod.stg_customers <> jaffle_shop.dev.stg_customers 
+        Primary Keys: ['customer_id'] 
+        No row differences
+        """
+
+        stg_orders_expected_output = """
+        jaffle_shop.prod.stg_orders <> jaffle_shop.dev.stg_orders 
+        Primary Keys: ['order_id'] 
+        No row differences
+        """
+
+        customers_expected_output = """
+        jaffle_shop.prod.customers <> jaffle_shop.dev.customers 
+        Primary Keys: ['customer_id'] 
+        No row differences
+        """
+
+        expected_outputs = [
+            orders_expected_output,
+            stg_payments_expected_output,
+            stg_customers_expected_output,
+            stg_orders_expected_output,
+            customers_expected_output,
+        ]
+
         if test_project_path == artifacts_path:
-            diff_string = b"".join(diff).decode("utf-8")
-            # 5 diffs were ran
-            assert diff_string.count("<>") == 5
-            # 4 with no diffs
-            assert diff_string.count("No row differences") == 4
-            # 1 with a diff
-            assert diff_string.count("  Rows Added    Rows Removed") == 1
+            actual_output_stripped = b"".join(diff).decode("utf-8").strip().replace(" ", "")
+
+            for expected_output in expected_outputs:
+                expected_output_stripped = "".join(line.strip() for line in expected_output.split("\n")).replace(
+                    " ", ""
+                )
+                assert expected_output_stripped in actual_output_stripped
 
     @unittest.skipIf(
         not os.environ.get("MOTHERDUCK_TOKEN"),
@@ -61,12 +121,19 @@ def test_integration_motherduck_dbt(self):
         # assertions for the diff that exists in tests/dbt_artifacts/jaffle_shop.duckdb
         if test_project_path == artifacts_path:
             diff_string = b"".join(diff).decode("utf-8")
-            # 5 diffs were ran
-            assert diff_string.count("<>") == 5
             # 4 with no diffs
             assert diff_string.count("No row differences") == 4
             # 1 with a diff
-            assert diff_string.count("  Rows Added    Rows Removed") == 1
+            assert diff_string.count("PROD") == 1
+            assert diff_string.count("DEV") == 1
+            assert diff_string.count("Primary Keys") == 5
+            assert diff_string.count("Where Filter") == 1
+            assert diff_string.count("Type Changed") == 0
+            assert diff_string.count("Total") == 1
+            assert diff_string.count("Added") == 1
+            assert diff_string.count("Removed") == 1
+            assert diff_string.count("Different") == 1
+            assert diff_string.count("Unchanged") == 1
 
     def test_integration_cloud_dbt(self):
         project_dir = os.environ.get("DATA_DIFF_DBT_PROJ")
@@ -231,6 +298,8 @@ def test_cloud_diff(self, mock_api, mock_os_environ, mock_print):
         expected_primary_keys = ["primary_key_column"]
         threads = None
         where = "a_string"
+        include_columns = ["created_at", "num_users", "sub_created_at", "sub_plan"]
+        exclude_columns = ["new_column"]
         connection = {}
         mock_api.create_data_diff.return_value = {"id": 123}
         mock_os_environ.get.return_value = expected_api_key
@@ -242,8 +311,8 @@ def test_cloud_diff(self, mock_api, mock_os_environ, mock_print):
             connection=connection,
             threads=threads,
             where_filter=where,
-            include_columns=[],
-            exclude_columns=[],
+            include_columns=include_columns,
+            exclude_columns=exclude_columns,
         )
 
         _cloud_diff(diff_vars, expected_datasource_id, org_meta=org_meta, api=mock_api)
@@ -257,8 +326,8 @@ def test_cloud_diff(self, mock_api, mock_os_environ, mock_print):
         self.assertEqual(payload.table1, prod_qualified_list)
         self.assertEqual(payload.table2, dev_qualified_list)
         self.assertEqual(payload.pk_columns, expected_primary_keys)
-        self.assertEqual(payload.filter1, where)
-        self.assertEqual(payload.filter2, where)
+        self.assertEqual(payload.include_columns, include_columns)
+        self.assertEqual(payload.exclude_columns, exclude_columns)
 
     @patch("data_diff.dbt._initialize_api")
     @patch("data_diff.dbt._get_diff_vars")
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 8972bd05d..712f3467c 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,6 +1,18 @@
 import unittest
+import re
+
+from data_diff.utils import (
+    remove_passwords_in_dict,
+    match_regexps,
+    match_like,
+    number_to_human,
+    diff_int_dynamic_color_template,
+    dbt_diff_string_template,
+    columns_removed_template,
+    columns_added_template,
+    columns_type_changed_template,
+)
 
-from data_diff.utils import remove_passwords_in_dict, match_regexps, match_like, number_to_human
 from data_diff.__main__ import _remove_passwords_in_dict
 
 
@@ -123,3 +135,79 @@ def test_number_to_human(self):
         assert number_to_human(-1000) == "-1k"
         assert number_to_human(-1000000) == "-1m"
         assert number_to_human(-1000000000) == "-1b"
+
+
+class TestDiffIntDynamicColorTemplate(unittest.TestCase):
+    def test_string_input(self):
+        self.assertEqual(diff_int_dynamic_color_template("test_string"), "test_string")
+
+    def test_positive_diff_value(self):
+        self.assertEqual(diff_int_dynamic_color_template(10), "[green]+10[/]")
+
+    def test_negative_diff_value(self):
+        self.assertEqual(diff_int_dynamic_color_template(-10), "[red]-10[/]")
+
+    def test_zero_diff(self):
+        self.assertEqual(diff_int_dynamic_color_template(0), "0")
+
+
+class TestDbtDiffStringTemplateNoMock(unittest.TestCase):
+    def test_dbt_diff_string_template(self):
+        self.maxDiff = None
+
+        expected_output = """
+rows       PROD    <>            DEV
+---------  ------  ------------  ------------------
+Total      10                    20 [[green]+10[/]]
+Added              [green]+5[/]
+Removed            [red]-2[/]
+Different          3
+Unchanged          5
+
+columns    # diff values
+---------  ---------------
+info       values
+
+deps    # data assets
+------  ---------------
+dep     assets"""
+
+        output = dbt_diff_string_template(
+            total_rows_table1=10,
+            total_rows_table2=20,
+            total_rows_diff=10,
+            rows_added=5,
+            rows_removed=2,
+            rows_updated=3,
+            rows_unchanged=5,
+            extra_info_dict={"info": "values"},
+            extra_info_str="extra info",
+            is_cloud=False,
+            deps_impacts={"dep": "assets"},
+        )
+
+        self.assertEqual(output, expected_output)
+
+
+class TestColumnsTemplateMethods(unittest.TestCase):
+    def extract_columns_set(self, output):
+        # Extract quoted words by regex
+        output_list = re.findall(r"'(\w*)'", output)
+        # Convert list to set
+        output_set = set(output_list)
+        return output_set
+
+    def test_columns_removed_template(self):
+        output = columns_removed_template({"column1", "column2"})
+        self.assertIn("[red]Columns removed [-2]:[/]", output)
+        self.assertEqual(self.extract_columns_set(output), {"column1", "column2"})
+
+    def test_columns_added_template(self):
+        output = columns_added_template({"column1", "column2"})
+        self.assertIn("[green]Columns added [+2]:", output)
+        self.assertEqual(self.extract_columns_set(output), {"column1", "column2"})
+
+    def test_columns_type_changed_template(self):
+        output = columns_type_changed_template({"column1", "column2"})
+        self.assertIn("Type changed [2]: [green]", output)
+        self.assertEqual(self.extract_columns_set(output), {"column1", "column2"})

From b75ceea857d7112b59fefbf07a0920490b7a4325 Mon Sep 17 00:00:00 2001
From: Leo Folsom <leoebfolsom@gmail.com>
Date: Wed, 7 Feb 2024 14:12:35 -0800
Subject: [PATCH 94/99] clarify that SQL Server support is limited (#864)

---
 README.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 4353f00a3..9a4587879 100644
--- a/README.md
+++ b/README.md
@@ -163,7 +163,7 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Redshift      |  🟢     | `redshift://<username>:<password>@<hostname>:5439/<database>`                                                                       |
 | DuckDB        |  🟢   | `duckdb://<filepath>`                                                                                          |
 | MotherDuck        |  🟢   | `duckdb://<filepath>`                                                                                                   |
-| Microsoft SQL Server        |  🟢   | `mssql://<user>:<password>@<host>/<database>/<schema>`                                                                                                   |
+| Microsoft SQL Server*        |  🟢   | `mssql://<user>:<password>@<host>/<database>/<schema>`                                                                                                   |
 | Oracle        |  🟡   | `oracle://<username>:<password>@<hostname>/servive_or_sid`                                                                          |
 | Presto        |  🟡   | `presto://<username>:<password>@<hostname>:8080/<database>`                                                                         |
 | Databricks    |  🟡   | `databricks://<http_path>:<access_token>@<server_hostname>/<catalog>/<schema>`                                                      |
@@ -175,6 +175,7 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Pinot         |  📝    |                                                                                                                                     |
 | Druid         |  📝    |                                                                                                                                     |                                                                                                                                  |
 | SQLite        |  📝    |                                                                                                                                     |
+*MS SQL Server support is limited, with known performance issues that are addressed in Datafold Cloud.
 
 * 🟢: Implemented and thoroughly tested.
 * 🟡: Implemented, but not thoroughly tested yet.

From f2a1b8d12b88b22b1f35f0b378f5da2329ca5970 Mon Sep 17 00:00:00 2001
From: Leo Folsom <leoebfolsom@gmail.com>
Date: Wed, 7 Feb 2024 14:32:29 -0800
Subject: [PATCH 95/99] formatting update to readme (#865)

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 9a4587879..82dff770d 100644
--- a/README.md
+++ b/README.md
@@ -175,6 +175,7 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Pinot         |  📝    |                                                                                                                                     |
 | Druid         |  📝    |                                                                                                                                     |                                                                                                                                  |
 | SQLite        |  📝    |                                                                                                                                     |
+
 *MS SQL Server support is limited, with known performance issues that are addressed in Datafold Cloud.
 
 * 🟢: Implemented and thoroughly tested.

From 962c9580b2d5582a14abd37755dcef6b6812d239 Mon Sep 17 00:00:00 2001
From: Sergey Vasilyev <sv@datafold.com>
Date: Mon, 19 Feb 2024 12:42:30 +0100
Subject: [PATCH 96/99] Loosen the restrictions of dependencies versions: >=
 instead of ^ and =

This is a library, so it must allow newer versions of dependencies in the virtualenv of the app, it should not restrict them to specific versions.
---
 data_diff/version.py |  2 +-
 poetry.lock          | 35 ++++++++++++++++++++++++++++++++---
 pyproject.toml       | 36 ++++++++++++++++++------------------
 3 files changed, 51 insertions(+), 22 deletions(-)

diff --git a/data_diff/version.py b/data_diff/version.py
index ae6db5f17..fee46bd8c 100644
--- a/data_diff/version.py
+++ b/data_diff/version.py
@@ -1 +1 @@
-__version__ = "0.11.0"
+__version__ = "0.11.1"
diff --git a/poetry.lock b/poetry.lock
index f4b6a6ccb..f75f82ae4 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
 
 [[package]]
 name = "agate"
@@ -324,6 +324,7 @@ python-versions = ">=3.7, <4"
 files = [
     {file = "clickhouse-driver-0.2.6.tar.gz", hash = "sha256:028baf4d65a0b3f9e0ac5df248cab20657b51adbfce6c5427aa6c16a7318dda1"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e61d975081b74cae9efe7a64b1de1a8aec5643affb81b57487dcae7d195f250f"},
+    {file = "clickhouse_driver-0.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee0395b49bd8c0cd3dca6b3a4b9db347c1d300de83ee7b4f482a9d48b6c7af54"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1d8aff4d3f0d78fd4b11e28ef344a5ee71d6850fef4a79e3265e0728b4d1d89"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b086bd658889af10205cb8307b714c8202bdfd05a4833fc7f4f82df2d88a963"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a1b6815d56a03398110c7f602a87ad767ecfd7a0869e61f2d8bfa0779dce2b"},
@@ -337,6 +338,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1960244de84d7888598180e69689d1ba7ec6c9c99cd2c080a76315a7a29a5cab"},
     {file = "clickhouse_driver-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:5a6bdfde4e2fb81414200303950ba75c3f7ee9249e4a997854ce18e1cb4beea9"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef0a9453a972ec32399cc93a510aec33fa4b9b1f0c5050a3a40e5d298a89a7aa"},
+    {file = "clickhouse_driver-0.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:95c13374741a8749980436603922ad7c476ae3b5e17850c50faba3879db66bdb"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d715d392eaadb43ded1c104354aebbc233f69bbf3919aa61beb7cc6ecdaa950a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91d75d50265616a2779d0b2acaebf7253783e2b8ad0df3efa6d23f0db1c9bf50"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32f0e02c28e9a6f1c1f116d1aa14772e73beb7efd4f30490d9f171d39b40551a"},
@@ -349,6 +351,20 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3bdff826074af1b339fe9bff17844f6b8117080f895b8601f536b13a9d04f82a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win32.whl", hash = "sha256:c8c02606eabe4288045bbba497088b7fe976c34330c1066db9744fa09fef4a2a"},
     {file = "clickhouse_driver-0.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:44df94940739a72a02716bb14ac8b683aef84b54b05783d96201ff334bcd88fb"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:079708ac620343736c2c8dace6663178156f4ded47bf25245b56147498d0d7de"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e13369cf516df6c33c156fe66cfff502f66fc25f2a515c761ed1480fc83b3aa9"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbc0bf957fc6d0163ee06ac02275bdb2f40d109fc225366e387358e78d968a43"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f58b0ffb434fefe99b7419e09d6071a49773e9eb49c5ebeedf7c3180b40c2330"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0746dac9aa5cf2c275187aef16b67ae922ef257c82671948a6be86e19ee9cb2"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f1ce40c9a2715ea44be9a5c33cb5b08048c1ef5595a6739443473e4ba23fedf"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9499a2b2d5e856c7e8efd28da479df8a962e2497c70bf5e2d9a25875d520465"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8b2e849bb7102365a480d9d1083ed203a244f0c02a0fc973eab6078b3d14638d"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:5846c50e2dfe0ce2f300275955a20f82422b1128b09ab5a9ea4d8a00d4ba8438"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:a12990b54b92b2a2598f144388e766d6261492408f2434738fe649423371894b"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:af14a5699fea890a1f8f022c624ca9f61994e15913cfaf4e0e58b1e4ac99540a"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:965fb8370eb7ee8a20cdf54d7c2fe024f587da692bd15e94dd2eee93a3c88f4b"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-win32.whl", hash = "sha256:9c552205d2b6125a99121080417c5c7bbc47af81ed15bb5ff9be464fed96bb68"},
+    {file = "clickhouse_driver-0.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:a58fb8b12a32d58ce0c72839293ec5bacc7904f3db36a82bb963f394dbb5f230"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f2a9abb8b1464985f7a480f956744736e611970ffc8ffd3eb0b46343a3a691e6"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e01696c450a2de41d586689dbaed0893d4de7469811abd3bf831a0483e723a"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0bb85760dabbef493aec985ad94612132ddeb5b81569cf0a7222f6cb7278eda"},
@@ -363,6 +379,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:48f47694d5e54af192a4aa2a24f947795c362ab40a253d088593880fede97568"},
     {file = "clickhouse_driver-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b783e5d3d12947c73d991bceb6b8765231512ab0ac6363823cdcd2c283c67a99"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3d24e0acf8fef1d787851ae048e0168b2fb10297c3235cbb87974f78db37d3d3"},
+    {file = "clickhouse_driver-0.2.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27dc025f10a930aed453eec5ed9a0404e7b2db671da4a253109facf5c1ad1b4c"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d534c744b1b211241f8c58d2ad5fcfc465a0503011d9b9073c00e25507abcbf3"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:858b8039a1241591b63f368de9dbdef6c4e6466b6bf0e01d53d36f7091af7569"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21eb62e1de7d2d5483d121d1447e857030bf866d4f23572b0dedc515f9359cd0"},
@@ -376,6 +393,7 @@ files = [
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win32.whl", hash = "sha256:b9b775f70371a7333ac828fe2bbd9473c94e18728ac6b70b2865cdee1f0d551f"},
     {file = "clickhouse_driver-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:d13fe44620750abcd4c93c067d6e44c8a1ea050856c4c27a5633ad8ff197a689"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e17995752eef4f742976abab03ff3f5b81edb9b9218b151abaf3534055fcf2b8"},
+    {file = "clickhouse_driver-0.2.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8c23baf4b4185b3ee13332c05c201e242600e35deb8b0b0d95211e71d5eb3f59"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbd7e3e33d2bc5f32da2557e97299340a722f948790494a2e9efaed4635ff499"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c872e9fee17d278816fc30b4df4b10bedd8eec9efaa614c71725f147b00b30d"},
     {file = "clickhouse_driver-0.2.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c8af2761676cd306962a86cc87a4187efcfdaf253a0d908c8f8ef791277a7fe"},
@@ -999,6 +1017,16 @@ files = [
     {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
     {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"},
+    {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
     {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
@@ -1705,6 +1733,7 @@ files = [
     {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
     {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
     {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+    {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
     {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
     {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
     {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
@@ -2290,5 +2319,5 @@ vertica = ["vertica-python"]
 
 [metadata]
 lock-version = "2.0"
-python-versions = "^3.8.0"
-content-hash = "3ba4fe6135b2011602f98b947cbee7c33cc7ac6ec8d80bf620ec5b381d4706f3"
+python-versions = ">=3.8.0,<4.0"
+content-hash = "9803d9acd74fac1442ded4d53952f51806a479f228598100891bf48fa36d6bce"
diff --git a/pyproject.toml b/pyproject.toml
index 13663d8d1..83ff58985 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.11.0"
+version = "0.11.1"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"
@@ -21,47 +21,47 @@ classifiers = [
 ]
 packages = [{ include = "data_diff" }]
 [tool.poetry.dependencies]
-pydantic = "1.10.12"
-python = "^3.8.0"
+pydantic = ">=1.10.12"
+python = ">=3.8.0,<4.0"
 dsnparse = "<0.2.0"
-click = "^8.1"
+click = ">=8.1"
 rich = "*"
-toml = "^0.10.2"
-mysql-connector-python = {version="8.0.29", optional=true}
+toml = ">=0.10.2"
+mysql-connector-python = {version=">=8.0.29", optional=true}
 psycopg2 = {version="*", optional=true}
 snowflake-connector-python = {version = ">=3.0.2,<4.0.0", optional=true}
 cryptography = {version="*", optional=true}
-trino = {version="^0.314.0", optional=true}
+trino = {version=">=0.314.0", optional=true}
 presto-python-client = {version="*", optional=true}
 clickhouse-driver = {version="*", optional=true}
 duckdb = {version="*", optional=true}
 dbt-core = {version="^1.0.0"}
 keyring = "*"
-tabulate = "^0.9.0"
-preql = {version="^0.2.19", optional=true}
+tabulate = ">=0.9.0"
+preql = {version=">=0.2.19", optional=true}
 vertica-python = {version="*", optional=true}
 urllib3 = "<2"
 oracledb = {version = "*", optional=true}
-pyodbc = {version="^4.0.39", optional=true}
+pyodbc = {version=">=4.0.39", optional=true}
 typing-extensions = ">=4.0.1"
-attrs = "^23.1.0"
+attrs = ">=23.1.0"
 mashumaro = {version = ">=2.9,<3.11.0", extras = ["msgpack"]}
 
 [tool.poetry.dev-dependencies]
 parameterized = "*"
 unittest-parallel = "*"
-preql = "^0.2.19"
+preql = ">=0.2.19"
 mysql-connector-python = "*"
 psycopg2 = "*"
 snowflake-connector-python = ">=3.0.2,<4.0.0"
 cryptography = "*"
-trino = "^0.314.0"
-presto-python-client = "0.8.3"
+trino = ">=0.314.0"
+presto-python-client = ">=0.8.3"
 clickhouse-driver = "*"
 vertica-python = "*"
-duckdb = "^0.9.0"
-dbt-core = "^1.0.0"
-ruff = "^0.1.4"
+duckdb = ">=0.9.0"
+dbt-core = ">=1.0.0"
+ruff = ">=0.1.4"
 # google-cloud-bigquery = "*"
 # databricks-sql-connector = "*"
 
@@ -86,7 +86,7 @@ all-dbs = [
 ]
 
 [tool.poetry.group.dev.dependencies]
-pre-commit = "^3.5.0"
+pre-commit = ">=3.5.0"
 
 [build-system]
 requires = ["poetry-core>=1.0.0"]

From b4e2d4b626e31afafe9d1b5e33759f991e05b27b Mon Sep 17 00:00:00 2001
From: Leo Folsom <leoebfolsom@gmail.com>
Date: Tue, 12 Mar 2024 16:12:09 -0700
Subject: [PATCH 97/99] Update README.md (#876)

* Update README.md

Remove databases that are not planned from README.

* style fixes by ruff

---------

Co-authored-by: leoebfolsom <leoebfolsom@users.noreply.github.com>
---
 README.md                      | 7 -------
 data_diff/cloud/data_source.py | 9 +++------
 data_diff/diff_tables.py       | 7 +++----
 data_diff/joindiff_tables.py   | 3 +--
 data_diff/queries/extras.py    | 1 +
 data_diff/utils.py             | 4 +---
 6 files changed, 9 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index 82dff770d..5da51054e 100644
--- a/README.md
+++ b/README.md
@@ -170,18 +170,11 @@ Check out [documentation](https://docs.datafold.com/reference/open_source/cli) f
 | Trino         |  🟡   | `trino://<username>:<password>@<hostname>:8080/<database>`                                                                          |
 | Clickhouse    |  🟡   | `clickhouse://<username>:<password>@<hostname>:9000/<database>`                                                                     |
 | Vertica       |  🟡   | `vertica://<username>:<password>@<hostname>:5433/<database>`                                                                        |
-| ElasticSearch |  📝    |                                                                                                                                     |
-| Planetscale   |  📝    |                                                                                                                                     |
-| Pinot         |  📝    |                                                                                                                                     |
-| Druid         |  📝    |                                                                                                                                     |                                                                                                                                  |
-| SQLite        |  📝    |                                                                                                                                     |
 
 *MS SQL Server support is limited, with known performance issues that are addressed in Datafold Cloud.
 
 * 🟢: Implemented and thoroughly tested.
 * 🟡: Implemented, but not thoroughly tested yet.
-* ⏳: Implementation in progress.
-* 📝: Implementation planned. Contributions welcome.
 
 Your database not listed here?
 
diff --git a/data_diff/cloud/data_source.py b/data_diff/cloud/data_source.py
index 3f3b2e16f..5bab4985b 100644
--- a/data_diff/cloud/data_source.py
+++ b/data_diff/cloud/data_source.py
@@ -90,18 +90,15 @@ def create_ds_config(
 
 
 @overload
-def _cast_value(value: str, type_: Literal["integer"]) -> int:
-    ...
+def _cast_value(value: str, type_: Literal["integer"]) -> int: ...
 
 
 @overload
-def _cast_value(value: str, type_: Literal["boolean"]) -> bool:
-    ...
+def _cast_value(value: str, type_: Literal["boolean"]) -> bool: ...
 
 
 @overload
-def _cast_value(value: str, type_: Literal["string"]) -> str:
-    ...
+def _cast_value(value: str, type_: Literal["string"]) -> str: ...
 
 
 def _cast_value(value: str, type_: str) -> Union[bool, int, str]:
diff --git a/data_diff/diff_tables.py b/data_diff/diff_tables.py
index 31a01a075..4fc581f23 100644
--- a/data_diff/diff_tables.py
+++ b/data_diff/diff_tables.py
@@ -1,5 +1,5 @@
-"""Provides classes for performing a table diff
-"""
+"""Provides classes for performing a table diff"""
+
 import threading
 import time
 from abc import ABC, abstractmethod
@@ -284,8 +284,7 @@ def _diff_segments(
         level=0,
         segment_index=None,
         segment_count=None,
-    ):
-        ...
+    ): ...
 
     def _bisect_and_diff_tables(self, table1: TableSegment, table2: TableSegment, info_tree):
         if len(table1.key_columns) != len(table2.key_columns):
diff --git a/data_diff/joindiff_tables.py b/data_diff/joindiff_tables.py
index 2d5e631a2..2a0a40232 100644
--- a/data_diff/joindiff_tables.py
+++ b/data_diff/joindiff_tables.py
@@ -1,6 +1,5 @@
-"""Provides classes for performing a table diff using JOIN
+"""Provides classes for performing a table diff using JOIN"""
 
-"""
 from decimal import Decimal
 from functools import partial
 import logging
diff --git a/data_diff/queries/extras.py b/data_diff/queries/extras.py
index 7d67ae974..a8098c7ac 100644
--- a/data_diff/queries/extras.py
+++ b/data_diff/queries/extras.py
@@ -1,4 +1,5 @@
 "Useful AST classes that don't quite fall within the scope of regular SQL"
+
 from typing import Callable, Optional, Sequence
 
 import attrs
diff --git a/data_diff/utils.py b/data_diff/utils.py
index 8c8e27154..1d1405fdb 100644
--- a/data_diff/utils.py
+++ b/data_diff/utils.py
@@ -72,8 +72,7 @@ def match_regexps(regexps: Dict[str, Any], s: str) -> Sequence[tuple]:
 
 class CaseAwareMapping(MutableMapping[str, V]):
     @abstractmethod
-    def get_key(self, key: str) -> str:
-        ...
+    def get_key(self, key: str) -> str: ...
 
     def new(self, initial=()) -> Self:
         return type(self)(initial)
@@ -416,7 +415,6 @@ def get_from_dict_with_raise(dictionary: Dict, key: str, exception: Exception):
 
 
 class Vector(tuple):
-
     """Immutable implementation of a regular vector over any arithmetic value
 
     Implements a product order - https://en.wikipedia.org/wiki/Product_order

From d2e2822f0ab651449b864343a553f0937445da78 Mon Sep 17 00:00:00 2001
From: Nick Carchedi <ncarchedi@users.noreply.github.com>
Date: Fri, 17 May 2024 05:46:31 -0600
Subject: [PATCH 98/99] Update README.md

---
 README.md | 229 +-----------------------------------------------------
 1 file changed, 3 insertions(+), 226 deletions(-)

diff --git a/README.md b/README.md
index 5da51054e..17b472ef7 100644
--- a/README.md
+++ b/README.md
@@ -1,238 +1,15 @@
-<p align="center">
-    <a href="https://datafold.com/"><img alt="Datafold" src="https://user-images.githubusercontent.com/1799931/196497110-d3de1113-a97f-4322-b531-026d859b867a.png" width="30%" /></a>
-</p>
+### ⚠️ As of May 17, 2024, Datafold is no longer actively supporting or developing open source data-diff. We’re grateful to everyone who made contributions along the way. Please see [our blog post](https://www.datafold.com/blog/sunsetting-open-source-data-diff) for additional context on this decision.
 
-<h2 align="center">
-data-diff: Compare datasets fast, within or across SQL databases
+---
 
-![data-diff-logo](docs/data-diff-logo.png)
-</h2>
-<br>
-
-> [Join our live virtual lab series to learn how to set it up!](https://www.datafold.com/virtual-hands-on-lab)
-
-# What's a Data Diff?
-A data diff is the value-level comparison between two tables—used to identify critical changes to your data and guarantee data quality.
-
-There is a lot you can do with data-diff: you can test SQL code by comparing development or staging environment data to production, or compare source and target data to identify discrepancies when moving data between databases.
-
-# data-diff OSS & Datafold Cloud
-data-diff is an open source utility for running stateless diffs as a great single player experience.
-
-
-
-Scale up with [Datafold Cloud](https://www.datafold.com/) to make data diffing a company-wide experience to both supercharge your data diffing CLI experience (ex: data-diff --dbt --cloud) and run diffs manually in your CI process and within the Datafold UI. This includes [column-level lineage](https://www.datafold.com/column-level-lineage) with BI tool integrations, [CI testing](https://docs.datafold.com/deployment_testing/how_it_works/), faster cross-database diffing, and diff history.
-
-# Use Cases
-
-### Data Development Testing
-When developing SQL code, data-diff helps you validate and preview changes by comparing data between development/staging environments and production. Here's how it works:
-1. Make a change to your SQL code
-2. Run the SQL code to create a new dataset
-3. Compare this dataset with its production version or other iterations
-
-### Data Migration & Replication Testing
-data-diff is a powerful tool for comparing data when you're moving it between systems. Use it to ensure data accuracy and identify discrepancies during tasks like:
-- **Migrating** to a new data warehouse (e.g., Oracle -> Snowflake)
-- **Validating SQL transformations** from legacy solutions (e.g., stored procedures) to new transformation frameworks (e.g., dbt)
-- Continuously **replicating data** from an OLTP database to OLAP data warehouse (e.g., MySQL -> Redshift)
-
-# dbt Integration
-  <p align="left">
-  <img alt="dbt" src="https://seeklogo.com/images/D/dbt-logo-E4B0ED72A2-seeklogo.com.png" width="10%" />
-  </p>
-
-data-diff integrates with [dbt Core](https://github.com/dbt-labs/dbt-core) to seamlessly compare local development to production datasets.
-
-Learn more about how data-diff works with dbt:
-* Read our docs to get started with [data-diff & dbt](https://docs.datafold.com/development_testing/cli) or :eyes: **watch the [4-min demo video](https://www.loom.com/share/ad3df969ba6b4298939efb2fbcc14cde)**
-* dbt Cloud users should check out [Datafold's out-of-the-box deployment testing integration](https://www.datafold.com/data-deployment-testing)
-* Get support from the dbt Community Slack in [#tools-datafold](https://getdbt.slack.com/archives/C03D25A92UU)
-
-
-# Getting Started
-
-### ⚡ Validating dbt model changes between dev and prod
-Looking to use data-diff in dbt development?
-
-Development testing with Datafold enables you to see the impact of dbt code changes on data as you write the code, whether in your IDE or CLI.
-
- Head over to [our `data-diff` + `dbt` documentation](https://docs.datafold.com/development_testing/cli) to get started with a development testing workflow!
-
-### 🔀 Compare data tables between databases
-1. Install `data-diff` with adapters
-
-To compare data between databases, install `data-diff` with specific database adapters. For example, install it for PostgreSQL and Snowflake like this:
-
-```
-pip install data-diff 'data-diff[postgresql,snowflake]' -U
-```
-
-Additionally, you can install all open source supported database adapters as follows.
-```
-pip install data-diff 'data-diff[all-dbs]' -U
-```
-
-2. Run `data-diff` with connection URIs
-
-Then, we compare tables between PostgreSQL and Snowflake using the hashdiff algorithm:
-
-```bash
-data-diff \
-  postgresql://<username>:'<password>'@localhost:5432/<database> \
-  <table> \
-  "snowflake://<username>:<password>@<account>/<DATABASE>/<SCHEMA>?warehouse=<WAREHOUSE>&role=<ROLE>" \
-  <TABLE> \
-  -k <primary key column> \
-  -c <columns to compare> \
-  -w <filter condition>
-```
-3. Set up your configuration
-
-You can use a `toml` configuration file to run your `data-diff` job. In this example, we compare tables between MotherDuck (hosted DuckDB) and Snowflake using the hashdiff algorithm:
-
-```toml
-## DATABASE CONNECTION ##
-[database.duckdb_connection]
-  driver = "duckdb"
-  # filepath = "datafold_demo.duckdb" # local duckdb file example
-  # filepath = "md:" # default motherduck connection example
-  filepath = "md:datafold_demo?motherduck_token=${motherduck_token}" # API token recommended for motherduck connection
-
-[database.snowflake_connection]
-  driver = "snowflake"
-  database = "DEV"
-  user = "sung"
-  password = "${SNOWFLAKE_PASSWORD}" # or "<PASSWORD_STRING>"
-  # the info below is only required for snowflake
-  account = "${ACCOUNT}" # by33919
-  schema = "DEVELOPMENT"
-  warehouse = "DEMO"
-  role = "DEMO_ROLE"
-
-## RUN PARAMETERS ##
-[run.default]
-  verbose = true
-
-## EXAMPLE DATA DIFF JOB ##
-[run.demo_xdb_diff]
-  # Source 1 ("left")
-  1.database = "duckdb_connection"
-  1.table = "development.raw_orders"
-
-  # Source 2 ("right")
-  2.database = "snowflake_connection"
-  2.table = "RAW_ORDERS" # note that snowflake table names are case-sensitive
-
-  verbose = false
-```
-4. Run your `data-diff` job
-
-Make sure to export relevant environment variables as needed. For example, we compare data based on the earlier configuration:
-
-```bash
-
-# export relevant environment variables, example below
-export motherduck_token=<MOTHERDUCK_TOKEN>
-
-# run the configured data-diff job
-data-diff --conf datadiff.toml \
-  --run demo_xdb_diff \
-  -k "id" \
-  -c status
-
-# output example
-- 1, completed
-+ 1, returned
-```
-
-5. Review the output
-
-After running your data-diff job, review the output to identify and analyze differences in your data.
-
-Check out [documentation](https://docs.datafold.com/reference/open_source/cli) for the full command reference.
-
-# Supported databases
-
-| Database      | Status | Connection string                                                                                                                   |
-|---------------|-------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
-| PostgreSQL >=10 |  🟢   | `postgresql://<user>:<password>@<host>:5432/<database>`                                                                             |
-| MySQL         |  🟢     | `mysql://<user>:<password>@<hostname>:5432/<database>`                                                                              |
-| Snowflake     |  🟢     | `"snowflake://<user>[:<password>]@<account>/<database>/<SCHEMA>?warehouse=<WAREHOUSE>&role=<role>[&authenticator=externalbrowser]"` |
-| BigQuery      |  🟢     | `bigquery://<project>/<dataset>`                                                                                                    |
-| Redshift      |  🟢     | `redshift://<username>:<password>@<hostname>:5439/<database>`                                                                       |
-| DuckDB        |  🟢   | `duckdb://<filepath>`                                                                                          |
-| MotherDuck        |  🟢   | `duckdb://<filepath>`                                                                                                   |
-| Microsoft SQL Server*        |  🟢   | `mssql://<user>:<password>@<host>/<database>/<schema>`                                                                                                   |
-| Oracle        |  🟡   | `oracle://<username>:<password>@<hostname>/servive_or_sid`                                                                          |
-| Presto        |  🟡   | `presto://<username>:<password>@<hostname>:8080/<database>`                                                                         |
-| Databricks    |  🟡   | `databricks://<http_path>:<access_token>@<server_hostname>/<catalog>/<schema>`                                                      |
-| Trino         |  🟡   | `trino://<username>:<password>@<hostname>:8080/<database>`                                                                          |
-| Clickhouse    |  🟡   | `clickhouse://<username>:<password>@<hostname>:9000/<database>`                                                                     |
-| Vertica       |  🟡   | `vertica://<username>:<password>@<hostname>:5433/<database>`                                                                        |
-
-*MS SQL Server support is limited, with known performance issues that are addressed in Datafold Cloud.
-
-* 🟢: Implemented and thoroughly tested.
-* 🟡: Implemented, but not thoroughly tested yet.
-
-Your database not listed here?
-
-- Contribute a [new database adapter](https://github.com/datafold/data-diff/blob/master/docs/new-database-driver-guide.rst) – we accept pull requests!
-- [Get in touch](https://www.datafold.com/demo) about enterprise support and adding new adapters and features
-
-
-<br>
-
-# How it works
-
-`data-diff` efficiently compares data using two modes:
-
-**joindiff**: Ideal for comparing data within the same database, utilizing outer joins for efficient row comparisons. It relies on the database engine for computation and has consistent performance.
-
-**hashdiff**: Recommended for comparing datasets across different databases or large tables with minimal differences. It uses hashing and binary search, capable of diffing data across distinct database engines.
-
-<details>
-<summary>Click here to learn more about joindiff and hashdiff</summary>
-
-### `joindiff`
-* Recommended for comparing data within the same database
-* Uses the outer join operation to diff the rows as efficiently as possible within the same database
-* Fully relies on the underlying database engine for computation
-* Requires both datasets to be queryable with a single SQL query
-* Time complexity approximates JOIN operation and is largely independent of the number of differences in the dataset
-
-### `hashdiff`:
-* Recommended for comparing datasets across different databases
-* Can also be helpful in diffing very large tables with few expected differences within the same database
-* Employs a divide-and-conquer algorithm based on hashing and binary search
-* Can diff data across distinct database engines, e.g., PostgreSQL <> Snowflake
-* Time complexity approximates COUNT(*) operation when there are few differences
-* Performance degrades when datasets have a large number of differences
-
-</details>
-<br>
-
-For detailed algorithm and performance insights, explore [here](https://github.com/datafold/data-diff/blob/master/docs/technical-explanation.md), or head to our docs to [learn more about how Datafold diffs data](https://docs.datafold.com/data_diff/how-datafold-diffs-data).
+# data-diff: Compare datasets fast, within or across SQL databases
 
 ## Contributors
 
-We thank everyone who contributed so far!
-
-We'd love to see your face here: [Contributing Instructions](CONTRIBUTING.md)
-
 <a href="https://github.com/datafold/data-diff/graphs/contributors">
   <img src="https://contributors-img.web.app/image?repo=datafold/data-diff" />
 </a>
 
-<br>
-
-## Analytics
-
-* [Usage Analytics & Data Privacy](https://github.com/datafold/data-diff/blob/master/docs/usage_analytics.md)
-
-<br>
-
 ## License
 
 This project is licensed under the terms of the [MIT License](https://github.com/datafold/data-diff/blob/master/LICENSE).

From 94f79321a9371ac96303893b80ee03b5aaae8518 Mon Sep 17 00:00:00 2001
From: Nick Carchedi <ncarchedi@users.noreply.github.com>
Date: Fri, 17 May 2024 05:47:56 -0600
Subject: [PATCH 99/99] increment version

---
 pyproject.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index 83ff58985..d377e5c56 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "data-diff"
-version = "0.11.1"
+version = "0.11.2"
 description = "Command-line tool and Python library to efficiently diff rows across two different databases."
 authors = ["Datafold <data-diff@datafold.com>"]
 license = "MIT"
