castor-extractor 0.25.6__py3-none-any.whl → 0.25.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of castor-extractor might be problematic. Click here for more details.

CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.25.9 - 2025-10-09
4
+
5
+ * Snowflake: raise an exception when no database is available for extraction
6
+ * Databricks: raise an exception when no database is available for extraction
7
+ * BigQuery: raise an exception when no project is available for extraction
8
+
9
+ ## 0.25.8 - 2025-10-09
10
+
11
+ * Count: extracting queries and canvas_loads
12
+
13
+ ## 0.25.7 - 2025-10-07
14
+
15
+ * SqlServer: Ensure database consistency between query and engine
16
+
3
17
  ## 0.25.6 - 2025-10-06
4
18
 
5
19
  * PowerBi: Support additional authentication methods
@@ -11,7 +11,6 @@ def main():
11
11
 
12
12
  parser.add_argument("-H", "--host", help="MSSQL Host")
13
13
  parser.add_argument("-P", "--port", help="MSSQL Port")
14
- parser.add_argument("-d", "--database", help="MSSQL Database")
15
14
  parser.add_argument("-u", "--user", help="MSSQL User")
16
15
  parser.add_argument("-p", "--password", help="MSSQL Password")
17
16
 
@@ -47,7 +46,6 @@ def main():
47
46
 
48
47
  sqlserver.extract_all(
49
48
  host=args.host,
50
- database=args.database,
51
49
  port=args.port,
52
50
  user=args.user,
53
51
  password=args.password,
@@ -0,0 +1,5 @@
1
+ class NoDatabaseProvidedException(Exception):
2
+ def __init__(self):
3
+ super().__init__("""No database eligible for extraction.
4
+ If you are using the db_allow/db_block options, please make sure to use the correct case.
5
+ """)
@@ -26,17 +26,6 @@ class AbstractSourceClient(ABC):
26
26
  def execute(self, query: ExtractionQuery) -> Iterator[dict]:
27
27
  pass
28
28
 
29
- def set_database(self, database: Optional[str]) -> None:
30
- """
31
- Set the active database for this client.
32
-
33
- Some source technologies require establishing a new connection
34
- or using a different connection URI when switching databases.
35
-
36
- Default behaviour is to do nothing.
37
- """
38
- pass
39
-
40
29
 
41
30
  class SqlalchemyClient(AbstractSourceClient, ABC):
42
31
  def __init__(self, credentials: dict):
@@ -1,6 +1,20 @@
1
+ from typing import Optional
2
+
3
+
1
4
  class ExtractionQuery:
2
- """contains both statement and parameters for the query"""
5
+ """
6
+ Contains useful context to run the query:
7
+ - the sql statement itself
8
+ - parameters { ... }
9
+ - optionally, the target database (can be used to change the engine's URI)
10
+ """
3
11
 
4
- def __init__(self, statement: str, params: dict):
12
+ def __init__(
13
+ self,
14
+ statement: str,
15
+ params: dict,
16
+ database: Optional[str] = None,
17
+ ):
5
18
  self.statement = statement
6
19
  self.params = params
20
+ self.database = database
@@ -5,7 +5,9 @@ class CountAsset(ExternalAsset):
5
5
  """Count assets"""
6
6
 
7
7
  CANVASES = "canvases"
8
+ CANVAS_LOADS = "canvas_loads"
8
9
  CANVAS_PERMISSIONS = "canvas_permissions"
9
10
  CELLS = "cells"
10
11
  PROJECTS = "projects"
12
+ QUERIES = "queries"
11
13
  USERS = "users"
@@ -3,6 +3,7 @@ from dataclasses import asdict
3
3
  from typing import Any, Iterator
4
4
 
5
5
  from ....utils import load_file
6
+ from ....warehouse.abstract import TimeFilter
6
7
  from ....warehouse.bigquery import BigQueryClient
7
8
  from ..assets import (
8
9
  CountAsset,
@@ -27,18 +28,21 @@ class CountClient(BigQueryClient):
27
28
  super().__init__(asdict(credentials))
28
29
  self.project_id = credentials.project_id
29
30
  self.dataset_id = credentials.dataset_id
31
+ self.time_filter = TimeFilter.default() # setting current date - 1
30
32
 
31
33
  def _load_query(self, asset: CountAsset) -> str:
32
34
  query = load_file(
33
35
  f"{_QUERIES_FOLDER}/{asset.name.lower()}.sql", __file__
34
36
  )
35
37
  return query.format(
36
- project_id=self.project_id, dataset_id=self.dataset_id
38
+ project_id=self.project_id,
39
+ dataset_id=self.dataset_id,
40
+ extract_date=self.time_filter.day,
37
41
  )
38
42
 
39
43
  def fetch(self, asset: CountAsset) -> Iterator[dict[str, Any]]:
40
44
  """
41
- Fetch the asset given as param, by running a BigQuery query.
45
+ Fetch the asset given as a param by running a BigQuery query.
42
46
  """
43
47
  logger.info(f"Running BigQuery query to fetch: {asset.name}")
44
48
 
@@ -0,0 +1,14 @@
1
+ WITH view_count AS(
2
+ SELECT
3
+ canvas_key,
4
+ DATE(loaded_at) AS load_day
5
+ FROM `{project_id}.{dataset_id}.canvas_loads`
6
+ WHERE TRUE
7
+ AND date(loaded_at) = '{extract_date}'
8
+ )
9
+
10
+ SELECT
11
+ canvas_key,
12
+ COUNT(*) AS view_count
13
+ FROM view_count
14
+ GROUP BY canvas_key
@@ -0,0 +1,23 @@
1
+ WITH ranked_queries AS (
2
+ SELECT
3
+ cell_key,
4
+ connection_key,
5
+ query,
6
+ started_at,
7
+ ROW_NUMBER() OVER (
8
+ PARTITION BY cell_key
9
+ ORDER BY started_at DESC
10
+ ) AS rank
11
+ FROM `{project_id}.{dataset_id}.queries`
12
+ WHERE TRUE
13
+ AND DATE(started_at) = '{extract_date}'
14
+ )
15
+
16
+ SELECT
17
+ cell_key,
18
+ connection_key,
19
+ query,
20
+ started_at
21
+ FROM ranked_queries
22
+ WHERE TRUE
23
+ AND rank = 1
@@ -268,3 +268,7 @@ class SigmaClient(APIClient):
268
268
 
269
269
  else:
270
270
  raise ValueError(f"This asset {asset} is unknown")
271
+
272
+ def test_connection(self) -> None:
273
+ """Use credentials & verify requesting the API doesn't raise an error"""
274
+ self._auth.refresh_token()
@@ -48,10 +48,9 @@ class SQLExtractionProcessor:
48
48
  # dict > set > dict
49
49
  return [dict(t) for t in {tuple(d.items()) for d in data}]
50
50
 
51
- def _fetch(self, query: ExtractionQuery) -> Iterator[dict]:
51
+ def fetch(self, query: ExtractionQuery) -> Iterator[dict]:
52
52
  default: Callable[[], Iterator] = lambda: iter(()) # type: ignore
53
53
  decorator = safe_mode(self._safe_mode, default)
54
- self._client.set_database(query.database)
55
54
  decorated_execute = decorator(self._client.execute)
56
55
  return decorated_execute(query)
57
56
 
@@ -63,7 +62,7 @@ class SQLExtractionProcessor:
63
62
  for i, query in enumerate(queries):
64
63
  logger.info(f"Extracting {asset.value}: query {i + 1}/{total}")
65
64
  # concatenate results of all queries
66
- data = chain(data, self._fetch(query))
65
+ data = chain(data, self.fetch(query))
67
66
 
68
67
  if self._query_builder.needs_deduplication(asset):
69
68
  # cast the list to iterator, but the streaming pipeline is broken in that case
@@ -3,6 +3,7 @@ import os
3
3
  from abc import ABC, abstractmethod
4
4
  from typing import Optional
5
5
 
6
+ from ...utils import ExtractionQuery
6
7
  from .asset import WarehouseAsset
7
8
  from .time_filter import TimeFilter
8
9
 
@@ -20,25 +21,6 @@ class AssetNotSupportedError(NotImplementedError):
20
21
  super().__init__(msg)
21
22
 
22
23
 
23
- class ExtractionQuery:
24
- """
25
- Contains useful context to run the query:
26
- - the sql statement itself
27
- - parameters { ... }
28
- - optionally, the target database (can be used to change the engine's URI)
29
- """
30
-
31
- def __init__(
32
- self,
33
- statement: str,
34
- params: dict,
35
- database: Optional[str] = None,
36
- ):
37
- self.statement = statement
38
- self.params = params
39
- self.database = database
40
-
41
-
42
24
  class AbstractQueryBuilder(ABC):
43
25
  """
44
26
  Build queries necessary to extract warehouse assets.
@@ -2,6 +2,10 @@ import json
2
2
  import logging
3
3
  from typing import cast
4
4
 
5
+ from castor_extractor.exceptions import ( # type: ignore
6
+ NoDatabaseProvidedException,
7
+ )
8
+
5
9
  from ...logger import add_logging_file_handler
6
10
  from ...utils import LocalStorage, SafeMode, from_env, write_summary
7
11
  from ..abstract import (
@@ -62,6 +66,9 @@ def extract_all(**kwargs) -> None:
62
66
  db_blocked=kwargs.get("db_blocked"),
63
67
  dataset_blocked=kwargs.get("dataset_blocked"),
64
68
  )
69
+ projects = client.get_projects()
70
+ if not projects:
71
+ raise NoDatabaseProvidedException
65
72
 
66
73
  logger.info(f"Available projects: {client.get_projects()}\n")
67
74
 
@@ -2,6 +2,10 @@ import logging
2
2
  from datetime import date
3
3
  from typing import Optional
4
4
 
5
+ from castor_extractor.exceptions import ( # type: ignore
6
+ NoDatabaseProvidedException,
7
+ )
8
+
5
9
  from ...utils import AbstractStorage, LocalStorage, write_summary
6
10
  from ..abstract import (
7
11
  ADDITIONAL_LINEAGE_ASSETS,
@@ -177,6 +181,9 @@ def extract_all(**kwargs) -> None:
177
181
  db_blocked=kwargs.get("db_blocked"),
178
182
  )
179
183
 
184
+ if not client.databases():
185
+ raise NoDatabaseProvidedException
186
+
180
187
  storage = LocalStorage(directory=output_directory)
181
188
 
182
189
  extractor = DatabricksExtractionProcessor(
@@ -1,5 +1,9 @@
1
1
  import logging
2
2
 
3
+ from castor_extractor.exceptions import ( # type: ignore
4
+ NoDatabaseProvidedException,
5
+ )
6
+
3
7
  from ...utils import LocalStorage, from_env, write_summary
4
8
  from ..abstract import (
5
9
  CATALOG_ASSETS,
@@ -60,6 +64,14 @@ def _credentials(params: dict) -> dict:
60
64
  raise ValueError("missing password or private key")
61
65
 
62
66
 
67
+ def _get_database_names(
68
+ extractor: SQLExtractionProcessor, query_builder: SnowflakeQueryBuilder
69
+ ) -> set[str]:
70
+ db_query = query_builder.build(WarehouseAsset.DATABASE)
71
+ databases = list(extractor.fetch(db_query[0]))
72
+ return {db["database_name"] for db in databases}
73
+
74
+
63
75
  def extract_all(**kwargs) -> None:
64
76
  """
65
77
  Extract all assets from Snowflake and store the results in CSV files
@@ -85,6 +97,12 @@ def extract_all(**kwargs) -> None:
85
97
  storage=storage,
86
98
  )
87
99
 
100
+ database_names = _get_database_names(extractor, query_builder)
101
+ if not database_names:
102
+ raise NoDatabaseProvidedException
103
+
104
+ logger.info(f"Available databases: {database_names}\n")
105
+
88
106
  for group in extractable_asset_groups(SNOWFLAKE_ASSETS):
89
107
  for asset in group:
90
108
  logger.info(f"Extracting `{asset.value.upper()}` ...")
@@ -4,7 +4,8 @@ from typing import Optional
4
4
 
5
5
  from sqlalchemy import create_engine, text
6
6
 
7
- from ...utils import ExtractionQuery, SqlalchemyClient, uri_encode
7
+ from ...utils import SqlalchemyClient, uri_encode
8
+ from ..abstract import ExtractionQuery
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
 
@@ -50,12 +51,25 @@ class MSSQLClient(SqlalchemyClient):
50
51
  )
51
52
  return uri
52
53
 
54
+ def _set_database(self, database: Optional[str]) -> None:
55
+ """
56
+ To support SQL Server running on Azure, we must change the engine's
57
+ URI depending on the case:
58
+ - URI/database for database-scoped queries
59
+ - URI otherwise
60
+ https://learn.microsoft.com/en-us/sql/t-sql/language-elements/use-transact-sql?view=sql-server-2017#database_name
61
+ https://github.com/dbeaver/dbeaver/issues/5258
62
+ """
63
+ database_uri = f"{self._uri}/{database}" if database else self._uri
64
+ self._engine = create_engine(database_uri, **self._options)
65
+
53
66
  def execute(self, query: ExtractionQuery) -> Iterator[dict]:
54
67
  """
55
68
  Re-implements the SQLAlchemyClient execute function to ensure we consume
56
69
  the cursor before calling connection.close() as it wipes out the data
57
70
  otherwise
58
71
  """
72
+ self._set_database(query.database)
59
73
  connection = self.connect()
60
74
  try:
61
75
  proxy = connection.execute(text(query.statement), query.params)
@@ -64,18 +78,6 @@ class MSSQLClient(SqlalchemyClient):
64
78
  finally:
65
79
  self.close()
66
80
 
67
- def set_database(self, database: Optional[str]) -> None:
68
- """
69
- To support SQL Server running on Azure, we must change the engine's
70
- URI for each database-scoped query
71
- https://chatgpt.com/share/68de93c3-9550-8001-9d54-c5da86faa43c
72
- """
73
- if not database:
74
- return
75
- self.close()
76
- database_uri = f"{self._uri}/{database}"
77
- self._engine = create_engine(database_uri, **self._options)
78
-
79
81
  def get_databases(self) -> list[str]:
80
82
  result = self.execute(
81
83
  ExtractionQuery("SELECT name FROM sys.databases", {})
@@ -128,7 +130,11 @@ class MSSQLClient(SqlalchemyClient):
128
130
  FROM
129
131
  [{database}].sys.database_query_store_options
130
132
  """
131
- query = ExtractionQuery(sql, {})
133
+ query = ExtractionQuery(
134
+ statement=sql,
135
+ params={},
136
+ database=database,
137
+ )
132
138
  # 2 = READ_WRITE, which means the Query Store is activated
133
139
  return next(self.execute(query))["desired_state"] == 2
134
140
 
@@ -32,7 +32,6 @@ MSSQL_USER = "CASTOR_MSSQL_USER"
32
32
  MSSQL_PASSWORD = "CASTOR_MSSQL_PASSWORD" # noqa: S105
33
33
  MSSQL_HOST = "CASTOR_MSSQL_HOST"
34
34
  MSSQL_PORT = "CASTOR_MSSQL_PORT"
35
- MSSQL_DATABASE = "CASTOR_MSSQL_DATABASE"
36
35
 
37
36
 
38
37
  def _credentials(params: dict) -> dict:
@@ -43,7 +42,6 @@ def _credentials(params: dict) -> dict:
43
42
  "password": params.get("password") or from_env(MSSQL_PASSWORD),
44
43
  "host": params.get("host") or from_env(MSSQL_HOST),
45
44
  "port": params.get("port") or from_env(MSSQL_PORT),
46
- "database": params.get("database") or from_env(MSSQL_DATABASE),
47
45
  }
48
46
 
49
47
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: castor-extractor
3
- Version: 0.25.6
3
+ Version: 0.25.9
4
4
  Summary: Extract your metadata assets.
5
5
  Home-page: https://www.castordoc.com/
6
6
  License: EULA
@@ -216,6 +216,20 @@ For any questions or bug report, contact us at [support@coalesce.io](mailto:supp
216
216
 
217
217
  # Changelog
218
218
 
219
+ ## 0.25.9 - 2025-10-09
220
+
221
+ * Snowflake: raise an exception when no database is available for extraction
222
+ * Databricks: raise an exception when no database is available for extraction
223
+ * BigQuery: raise an exception when no project is available for extraction
224
+
225
+ ## 0.25.8 - 2025-10-09
226
+
227
+ * Count: extracting queries and canvas_loads
228
+
229
+ ## 0.25.7 - 2025-10-07
230
+
231
+ * SqlServer: Ensure database consistency between query and engine
232
+
219
233
  ## 0.25.6 - 2025-10-06
220
234
 
221
235
  * PowerBi: Support additional authentication methods
@@ -1,4 +1,4 @@
1
- CHANGELOG.md,sha256=_zH2Mm-Bn_xdVUaseScAbBos3i0Ae_MspceXsG-5vjc,21437
1
+ CHANGELOG.md,sha256=_a0SAY_yUw6oLXAGY2GZRZmOytS5lHUVP6-6mLD1XgY,21853
2
2
  Dockerfile,sha256=xQ05-CFfGShT3oUqaiumaldwA288dj9Yb_pxofQpufg,301
3
3
  DockerfileUsage.md,sha256=2hkJQF-5JuuzfPZ7IOxgM6QgIQW7l-9oRMFVwyXC4gE,998
4
4
  LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
@@ -25,12 +25,13 @@ castor_extractor/commands/extract_salesforce.py,sha256=3j3YTmMkPAwocR-B1ozJQai0U
25
25
  castor_extractor/commands/extract_salesforce_reporting.py,sha256=FdANTNiLkIPdm80XMYxWReHjdycLsIa61pyeCD-sUDk,962
26
26
  castor_extractor/commands/extract_sigma.py,sha256=sxewHcZ1Doq35V2qnpX_zCKKXkrb1_9bYjUMg7BOW-k,643
27
27
  castor_extractor/commands/extract_snowflake.py,sha256=GwlrRxwEBjHqGs_3bs5vM9fzmv61_iwvBr1KcIgFgWM,2161
28
- castor_extractor/commands/extract_sqlserver.py,sha256=zwPITImztIIyIbZJyE1SioGraVrlRfxgLq_vHX6l5l0,1664
28
+ castor_extractor/commands/extract_sqlserver.py,sha256=NNYfAOG-NJX0F_q0yBD-msIiwyp04Ne3fJs8hggv6YQ,1565
29
29
  castor_extractor/commands/extract_strategy.py,sha256=Q-pUymatPrBFGXobhyUPzFph0-t774-XOpjdCFF1dYo,821
30
30
  castor_extractor/commands/extract_tableau.py,sha256=cfH-b0Hq9LGrQSJv02Yr_4d6oNqhxwDqUcKraE-5fRc,2134
31
31
  castor_extractor/commands/extract_thoughtspot.py,sha256=caAYJlH-vK7u5IUB6OKXxcaWfLgc7d_XqnFDWK6YNS4,639
32
32
  castor_extractor/commands/file_check.py,sha256=TJx76Ymd0QCECmq35zRJMkPE8DJtSInB28MuSXWk8Ao,2644
33
33
  castor_extractor/commands/upload.py,sha256=sqpEF_qqCNvT_niIrM6jPhzLaFVjtYwpc2iZw540F20,1633
34
+ castor_extractor/exceptions.py,sha256=WypgqL8AxYL1viYUCSY4528pk5TRcqVNPvyLMMMDWGw,238
34
35
  castor_extractor/file_checker/__init__.py,sha256=OSt6YLhUT42U_Cp3LCLHMVruwDkksL75Ij13X2UPnVk,119
35
36
  castor_extractor/file_checker/column.py,sha256=6bJhcW1snYwgHKkqlS0Ak7XLHZr4YBwO46JCIlnQNKg,3086
36
37
  castor_extractor/file_checker/column_test.py,sha256=1j8PxvmvmJgpd-mk30iMYOme32ovPSIn4yCXywFoXrg,1935
@@ -102,7 +103,7 @@ castor_extractor/utils/argument_parser_test.py,sha256=wnyLFJ74iEiPxxLSbwFtckR7FI
102
103
  castor_extractor/utils/batch.py,sha256=SFlLmJgVjV2nVhIrjVIEp8wJ9du4dKKHq8YVYubnwQQ,448
103
104
  castor_extractor/utils/batch_test.py,sha256=84JYXOxiTkZFAceVh0mzN6VtKxcqoFPbxkZfIDyLGlg,606
104
105
  castor_extractor/utils/client/__init__.py,sha256=h5gm8UNNCCkAqhjYK5f6BY7k0cHFOyAvkmlktqwpir0,392
105
- castor_extractor/utils/client/abstract.py,sha256=OyTpb_SBgxaZd-4QFUV3n7yTzszAbyxY89fHsdAGKS8,2410
106
+ castor_extractor/utils/client/abstract.py,sha256=CWF7_afNpEZ3jor-22wXbKIvM20ukHkaDy_uknKz8B0,2075
106
107
  castor_extractor/utils/client/api/__init__.py,sha256=vlG7WXznYgLTn3XyMGsyUkgRkup8FbKM14EXJ8mv-b0,264
107
108
  castor_extractor/utils/client/api/auth.py,sha256=lq0K3UEl1vwIIa_vKTdlpIQPdE5K1-5DXmCwO4dKzng,1890
108
109
  castor_extractor/utils/client/api/auth_test.py,sha256=LlyXytnatg6ZzR4Zkvzk0BH99FYhHX7qn_nyr2MSnDI,1305
@@ -115,7 +116,7 @@ castor_extractor/utils/client/api/safe_request_test.py,sha256=LqS5FBxs6lLLcTkcgx
115
116
  castor_extractor/utils/client/api/utils.py,sha256=jr8CWf48cIp8QP1P7oZ1zg9WaGlDO3mqCWgQKdEcpyc,238
116
117
  castor_extractor/utils/client/api/utils_test.py,sha256=a5aL-pCwa74C8Ne7OT169Bjp8WPDV5Fl8MxNxAllHJg,514
117
118
  castor_extractor/utils/client/postgres.py,sha256=n6ulaT222WWPY0_6qAZ0MHF0m91HtI9mMqL71nyygo0,866
118
- castor_extractor/utils/client/query.py,sha256=O6D5EjD1KmBlwa786Uw4D4kzxx97_HH50xIIeSWt0B8,205
119
+ castor_extractor/utils/client/query.py,sha256=Ucbv8dq5xRziV4HusleY2eJE3Whp8fHsVeQlPeVTuLs,473
119
120
  castor_extractor/utils/client/uri.py,sha256=jmP9hY-6PRqdc3-vAOdtll_U6q9VCqSqmBAN6QRs3ZI,150
120
121
  castor_extractor/utils/client/uri_test.py,sha256=1XKF6qSseCeD4G4ckaNO07JXfGbt7XUVinOZdpEYrDQ,259
121
122
  castor_extractor/utils/collection.py,sha256=g2HmB0ievvYHWaZ8iEzkcPPkrBFsh6R6b_liBqcsMjc,3044
@@ -162,14 +163,16 @@ castor_extractor/utils/validation_test.py,sha256=A7P6VmI0kYX2aGIeEN12y7LsY7Kpm8p
162
163
  castor_extractor/utils/write.py,sha256=KQVWF29N766avzmSb129IUWrId5c_8BtnYhVLmU6YIs,2133
163
164
  castor_extractor/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
165
  castor_extractor/visualization/count/__init__.py,sha256=lvxGtSe3erjTYK0aPnkOyJibcsC6Q1AFchnK-hZt558,114
165
- castor_extractor/visualization/count/assets.py,sha256=VZCRVDKWSu6l2lVGJS4JKOOmfCUkbS8MnJiLcAY9vqw,232
166
+ castor_extractor/visualization/count/assets.py,sha256=zvj2FuCrZlyKPAd8lx5rgWPKsEQ0biQJCk7AEYj6qd0,290
166
167
  castor_extractor/visualization/count/client/__init__.py,sha256=YawYDutDI0sprp72jN9tKi8bbXCoc0Ij0Ev582tKjqk,74
167
- castor_extractor/visualization/count/client/client.py,sha256=WgljCj8G7D0Brxa0llaeOQ2Ipd7FvtDWFoLWoPyqT9A,1523
168
+ castor_extractor/visualization/count/client/client.py,sha256=vSrV8V3acQAz9Hc2_DKjeU500bx2FT-DHrzUwTdjroo,1706
168
169
  castor_extractor/visualization/count/client/credentials.py,sha256=LZWvcz7p5lrgdgoIQLcxFyv4gqUBW4Jj4qDKN-VW31I,273
170
+ castor_extractor/visualization/count/client/queries/canvas_loads.sql,sha256=suR5_X2SU9UIGwDi7mSxZrJvoh_-4WJwgtfBYnKMV1E,288
169
171
  castor_extractor/visualization/count/client/queries/canvas_permissions.sql,sha256=iFmMfR0zusjxTxmYUS6p0kibZCsnHOQMbAlxaNjx-H4,108
170
172
  castor_extractor/visualization/count/client/queries/canvases.sql,sha256=Ur5HBD9JJH0r14xIj_rwoctnds082_F931vlfcnwi_I,86
171
173
  castor_extractor/visualization/count/client/queries/cells.sql,sha256=Kkk0jyU337PD6RPshSo_ucLl5PS7kIvJZlUnVnmJUkM,111
172
174
  castor_extractor/visualization/count/client/queries/projects.sql,sha256=3Jem3QCVwk4wHiWRJL7cN6Vl2Yc5RZ8yC8ndvPAkaFM,68
175
+ castor_extractor/visualization/count/client/queries/queries.sql,sha256=ffnlRwMedTVoMzuXkQaTWw5oOP-Ties9vGCfQOXdhQ0,456
173
176
  castor_extractor/visualization/count/client/queries/users.sql,sha256=H0n7S7P5cCAWbgPxU32psIc1epXySzsAaQ7MQ9JrkfM,102
174
177
  castor_extractor/visualization/count/extract.py,sha256=ZBsJ9tMxxaq1jG8qJp_OGVK3yPDNkVUsP1_3rcUMtYg,1378
175
178
  castor_extractor/visualization/domo/__init__.py,sha256=1axOCPm4RpdIyUt9LQEvlMvbOPllW8rk63h6EjVgJ0Y,111
@@ -285,7 +288,7 @@ castor_extractor/visualization/sigma/__init__.py,sha256=GINql4yJLtjfOJgjHaWNpE13
285
288
  castor_extractor/visualization/sigma/assets.py,sha256=iVZqi7XtNgSOVXy0jgeHZonVOeXi7jyikor8ztbECBc,398
286
289
  castor_extractor/visualization/sigma/client/__init__.py,sha256=YQv06FBBQHvBMFg_tN0nUcmUp2NCL2s-eFTXG8rXaBg,74
287
290
  castor_extractor/visualization/sigma/client/authentication.py,sha256=gHukrpfboIjZc_O9CcuDtrl6U-StH0J73VY2J74Bm9o,2279
288
- castor_extractor/visualization/sigma/client/client.py,sha256=SxSf5OjdDr8x-WZDezm8YNOw01R6CCoYIgW0od0ZgN8,8907
291
+ castor_extractor/visualization/sigma/client/client.py,sha256=bYlOwtb6ftASb9onUSAHCdEiyfsY5H_KHWkQB4y2Y-o,9063
289
292
  castor_extractor/visualization/sigma/client/client_test.py,sha256=ae0ZOvKutCm44jnrJ-0_A5Y6ZGyDkMf9Ml3eEP8dNkY,581
290
293
  castor_extractor/visualization/sigma/client/credentials.py,sha256=XddAuQSmCKpxJ70TQgRnOj0vMPYVtiStk_lMMQ1AiNM,693
291
294
  castor_extractor/visualization/sigma/client/endpoints.py,sha256=by9VIFml2whlzQT66f2m56RYBsqPrWdAmIP4JkTaBV4,1799
@@ -326,15 +329,15 @@ castor_extractor/warehouse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
326
329
  castor_extractor/warehouse/abstract/__init__.py,sha256=Fdfa026tgOo64MvzVRLHM_F2G-JmcehrF0mh3dHgb7s,419
327
330
  castor_extractor/warehouse/abstract/asset.py,sha256=wR5mJxAHBcqJ86HRb_Y8x3mDN4uUgSg8jMToLNu0jTM,2740
328
331
  castor_extractor/warehouse/abstract/asset_test.py,sha256=_kd4ybNlWSAdSdEgJKC-jhJTa1nMRa9i8RO3YbqKLM4,758
329
- castor_extractor/warehouse/abstract/extract.py,sha256=T_GwXO4_IFSVdBuMmnKvsftl549y43nzE5uN4He4G80,2974
330
- castor_extractor/warehouse/abstract/query.py,sha256=MSOou0F5BlTths1TsAxv9tcyOB013aJc1TegN4q7jfM,2852
332
+ castor_extractor/warehouse/abstract/extract.py,sha256=a3Poqm1hF6NQQNAWQVib9_uj41LcvXzoX8IQCPCT66c,2922
333
+ castor_extractor/warehouse/abstract/query.py,sha256=h1VvSo6TpyS1myRqmPtoIFY1fVgbthsHOkkajUz-PKA,2444
331
334
  castor_extractor/warehouse/abstract/time_filter.py,sha256=bggIONfMmUxffkA6TwM3BsjfS2l9WFxPq8krfsau5pw,935
332
335
  castor_extractor/warehouse/abstract/time_filter_test.py,sha256=PIkegB7KOKBdpc6zIvmyl_CeQyADeFDplyQ8HTNU5LA,448
333
336
  castor_extractor/warehouse/bigquery/__init__.py,sha256=PCGNYdi7dHv-SyanUWzRuBp-ypuQ01PkDaQjVnaNhbM,170
334
337
  castor_extractor/warehouse/bigquery/client.py,sha256=lPAn6WUwDq0rIPNaMOcabet8C4TYJ93EWZUxX72XrZc,5595
335
338
  castor_extractor/warehouse/bigquery/client_test.py,sha256=Ym8e4d--0YQwiVcNUnXLx0X-X6ZznwNMBMbMaDS5oEA,1514
336
339
  castor_extractor/warehouse/bigquery/credentials.py,sha256=oCZ8H7qpudKzwM7PRMpVAmWXt7bjIRa8Harmp-ysQJ4,425
337
- castor_extractor/warehouse/bigquery/extract.py,sha256=TAxpdwZ6kfSe7xv22vcFwAE3-Rr1VF9UnX0DM_IPdF8,2934
340
+ castor_extractor/warehouse/bigquery/extract.py,sha256=4zdqzUROktteGLEpssxT-23shyD7UqWcrs8Mey5MsXA,3128
338
341
  castor_extractor/warehouse/bigquery/queries/.sqlfluff,sha256=ce8UDW2k39v6RBVxgKqjOHHYMoGN9S9f7BCZNHHhox8,30
339
342
  castor_extractor/warehouse/bigquery/queries/column.sql,sha256=NxdTnHwomHTEGSc-UoXFKUwg59I9XAOwrSau7JUqGQE,1815
340
343
  castor_extractor/warehouse/bigquery/queries/cte/sharded.sql,sha256=-G7_4lxV7UPe72mYlp4HDGeM_fJjZWuXJ7Q0vxvj5_U,1454
@@ -355,7 +358,7 @@ castor_extractor/warehouse/databricks/client_test.py,sha256=dqEdEAt-6e8CtQ7M2L5v
355
358
  castor_extractor/warehouse/databricks/credentials.py,sha256=ExtVcl2NpMXTx1Lg8vHQdzQtSEm2aqpg3D1BJrNAUjI,528
356
359
  castor_extractor/warehouse/databricks/endpoints.py,sha256=qPoL9CtPFJdwVuW9rJ37nmeMd-nChOBouEVYb4SlaUE,670
357
360
  castor_extractor/warehouse/databricks/enums.py,sha256=3T6BbVvbWvfWkD23krsYT1x0kKh1qRzNPl6WpcXe300,274
358
- castor_extractor/warehouse/databricks/extract.py,sha256=Z4VTEIf0QMiua0QGAlJdQ86kxmGAXekQ304aCKme6IY,7358
361
+ castor_extractor/warehouse/databricks/extract.py,sha256=u3WJV5bnVKYhGx_yJ_yYyxZjuMw5uC3ehiM_zQeoQwk,7526
359
362
  castor_extractor/warehouse/databricks/format.py,sha256=S3BOcwJubc1pyKr-li26uftUUfsjfrm5Qf4LqmElXVk,6736
360
363
  castor_extractor/warehouse/databricks/format_test.py,sha256=ls0IcOElqp_qecAzNbK0zdca7Pms4seCHimbw8NAoAI,3322
361
364
  castor_extractor/warehouse/databricks/pagination.py,sha256=sM1G0sN1pf1TPpI0Y3Oew378UGEKVkMRc2Mlu9tDjLo,545
@@ -418,7 +421,7 @@ castor_extractor/warehouse/snowflake/client.py,sha256=RB72bbl_k91wDU76yrggPK6oeE
418
421
  castor_extractor/warehouse/snowflake/client_test.py,sha256=ihWtOOAQfh8pu5JTr_EWfqefKOVIaJXznACURzaU1Qs,1432
419
422
  castor_extractor/warehouse/snowflake/credentials.py,sha256=u0sZ6xPtcZmmvnUsAejJk-YxGl8BTzX_BlRjRk92BYU,932
420
423
  castor_extractor/warehouse/snowflake/credentials_test.py,sha256=Lkc-DHXOvr50KrqAW4nt_x0IA0Mu_CsBVu6ATnzQB6I,673
421
- castor_extractor/warehouse/snowflake/extract.py,sha256=eGtIqW5kKJl-e36viqYQzkXn39CJkmMBR4oSt-B0ud4,3082
424
+ castor_extractor/warehouse/snowflake/extract.py,sha256=E7mJsJneCofYoAgyQpc7Th2gKxsyZm2cRr1iADDAcl0,3656
422
425
  castor_extractor/warehouse/snowflake/queries/.sqlfluff,sha256=vttrwcr64JVIuvc7WIg9C54cbOkjg_VjXNR7YnTGOPE,31
423
426
  castor_extractor/warehouse/snowflake/queries/column.sql,sha256=Ru-yC0s76I9LehOA4aCZ--xz6D9H1Hyr3OZdILOBHAw,1882
424
427
  castor_extractor/warehouse/snowflake/queries/column_lineage.sql,sha256=YKBiZ6zySSNcXLDXwm31EjGIIkkkZc0-S6hI1SRM80o,1179
@@ -431,8 +434,8 @@ castor_extractor/warehouse/snowflake/queries/user.sql,sha256=88V8eRj1NDaD_ufclsK
431
434
  castor_extractor/warehouse/snowflake/queries/view_ddl.sql,sha256=eWsci_50cxiYIv3N7BKkbXVM3RoIzqSDtohqRnE5kg4,673
432
435
  castor_extractor/warehouse/snowflake/query.py,sha256=C2LTdPwBzMQ_zMncg0Kq4_WkoY7K9as5tvxBDrIOlwI,1763
433
436
  castor_extractor/warehouse/sqlserver/__init__.py,sha256=PdOuYznmvKAbfWAm8UdN47MfEsd9jqPi_dDi3WEo1KY,116
434
- castor_extractor/warehouse/sqlserver/client.py,sha256=umxTNZ92S2ImtxkPwzXdTzGvym-bjv5xSNK29vawL-8,5549
435
- castor_extractor/warehouse/sqlserver/extract.py,sha256=HEJFDM1a4OeQH7OWhYhCOjhkHfGW6qf_qvjFAeMGPYg,2623
437
+ castor_extractor/warehouse/sqlserver/client.py,sha256=ggqcOtGeDk9OMyqx7fO3p-2NsbFG8vT-GoHdRx5Iy_Q,5833
438
+ castor_extractor/warehouse/sqlserver/extract.py,sha256=PlYANeqCUrw3uy3HnMxkPT1W3WyRt-qxY9ECK3Sc2lM,2510
436
439
  castor_extractor/warehouse/sqlserver/queries/.sqlfluff,sha256=yy0KQdz8I_67vnXyX8eeWwOWkxTXvHyVKSVwhURktd8,48
437
440
  castor_extractor/warehouse/sqlserver/queries/column.sql,sha256=ojiUQQnHXdWMbgaYOcxKBiwfi7rtu_tyamK6r4t4IBM,2929
438
441
  castor_extractor/warehouse/sqlserver/queries/database.sql,sha256=4dPeBCn85MEOXr1f-DPXxiI3RvvoE_1n8lsbTs26E0I,150
@@ -443,8 +446,8 @@ castor_extractor/warehouse/sqlserver/queries/user.sql,sha256=MAlnTis43E3Amu1e1Oz
443
446
  castor_extractor/warehouse/sqlserver/queries/view_ddl.sql,sha256=9rynvx6MWg3iZzrWPB7haZfVKEPkxulzryE2g19x804,315
444
447
  castor_extractor/warehouse/sqlserver/query.py,sha256=gr5lnZSUm-wSYuVnJlg6fc7jXWirbL-sCiQN9RnAiPQ,1789
445
448
  castor_extractor/warehouse/synapse/queries/column.sql,sha256=lNcFoIW3Y0PFOqoOzJEXmPvZvfAsY0AP63Mu2LuPzPo,1351
446
- castor_extractor-0.25.6.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
447
- castor_extractor-0.25.6.dist-info/METADATA,sha256=ayaVswDaw-D2Zele6ewtVK5inUm9fBOuDik-AGY7yAY,28939
448
- castor_extractor-0.25.6.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
449
- castor_extractor-0.25.6.dist-info/entry_points.txt,sha256=qyTrKNByoq2HYi1xbA79OU7qxg-OWPvle8VwDqt-KnE,1869
450
- castor_extractor-0.25.6.dist-info/RECORD,,
449
+ castor_extractor-0.25.9.dist-info/LICENCE,sha256=sL-IGa4hweyya1HgzMskrRdybbIa2cktzxb5qmUgDg8,8254
450
+ castor_extractor-0.25.9.dist-info/METADATA,sha256=B5If1AjiP00k7LJDYd13LtlfRoDrxPylNJ5AmjWmFTA,29355
451
+ castor_extractor-0.25.9.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
452
+ castor_extractor-0.25.9.dist-info/entry_points.txt,sha256=qyTrKNByoq2HYi1xbA79OU7qxg-OWPvle8VwDqt-KnE,1869
453
+ castor_extractor-0.25.9.dist-info/RECORD,,