relationalai 0.11.2__py3-none-any.whl → 0.11.4__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.
- relationalai/clients/snowflake.py +44 -15
- relationalai/clients/types.py +1 -0
- relationalai/clients/use_index_poller.py +446 -178
- relationalai/early_access/builder/std/__init__.py +1 -1
- relationalai/early_access/dsl/bindings/csv.py +4 -4
- relationalai/semantics/internal/internal.py +22 -4
- relationalai/semantics/lqp/executor.py +69 -18
- relationalai/semantics/lqp/intrinsics.py +23 -0
- relationalai/semantics/lqp/model2lqp.py +16 -6
- relationalai/semantics/lqp/passes.py +3 -4
- relationalai/semantics/lqp/primitives.py +38 -14
- relationalai/semantics/metamodel/builtins.py +152 -11
- relationalai/semantics/metamodel/factory.py +3 -2
- relationalai/semantics/metamodel/helpers.py +78 -2
- relationalai/semantics/reasoners/graph/core.py +343 -40
- relationalai/semantics/reasoners/optimization/solvers_dev.py +20 -1
- relationalai/semantics/reasoners/optimization/solvers_pb.py +24 -3
- relationalai/semantics/rel/compiler.py +5 -17
- relationalai/semantics/rel/executor.py +2 -2
- relationalai/semantics/rel/rel.py +6 -0
- relationalai/semantics/rel/rel_utils.py +37 -1
- relationalai/semantics/rel/rewrite/extract_common.py +153 -242
- relationalai/semantics/sql/compiler.py +540 -202
- relationalai/semantics/sql/executor/duck_db.py +21 -0
- relationalai/semantics/sql/executor/result_helpers.py +7 -0
- relationalai/semantics/sql/executor/snowflake.py +9 -2
- relationalai/semantics/sql/rewrite/denormalize.py +4 -6
- relationalai/semantics/sql/rewrite/recursive_union.py +23 -3
- relationalai/semantics/sql/sql.py +120 -46
- relationalai/semantics/std/__init__.py +9 -4
- relationalai/semantics/std/datetime.py +363 -0
- relationalai/semantics/std/math.py +77 -0
- relationalai/semantics/std/re.py +83 -0
- relationalai/semantics/std/strings.py +1 -1
- relationalai/tools/cli_controls.py +445 -60
- relationalai/util/format.py +78 -1
- {relationalai-0.11.2.dist-info → relationalai-0.11.4.dist-info}/METADATA +3 -2
- {relationalai-0.11.2.dist-info → relationalai-0.11.4.dist-info}/RECORD +41 -39
- relationalai/semantics/std/dates.py +0 -213
- {relationalai-0.11.2.dist-info → relationalai-0.11.4.dist-info}/WHEEL +0 -0
- {relationalai-0.11.2.dist-info → relationalai-0.11.4.dist-info}/entry_points.txt +0 -0
- {relationalai-0.11.2.dist-info → relationalai-0.11.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -2048,7 +2048,7 @@ Otherwise, remove it from your '{profile}' configuration profile.
|
|
|
2048
2048
|
assert len(parsed) == 4, f"Invalid source: {source}"
|
|
2049
2049
|
db, schema, entity, identity = parsed
|
|
2050
2050
|
assert db and schema and entity and identity, f"Invalid source: {source}"
|
|
2051
|
-
source_types[identity] = cast(SourceInfo, {"type": None, "state": ""})
|
|
2051
|
+
source_types[identity] = cast(SourceInfo, {"type": None, "state": "", "columns_hash": None})
|
|
2052
2052
|
partitioned_sources[db][schema].append(entity)
|
|
2053
2053
|
|
|
2054
2054
|
# TODO: Move to NA layer
|
|
@@ -2057,6 +2057,7 @@ Otherwise, remove it from your '{profile}' configuration profile.
|
|
|
2057
2057
|
f"""SELECT
|
|
2058
2058
|
inf.FQN,
|
|
2059
2059
|
inf.KIND,
|
|
2060
|
+
inf.COLUMNS_HASH,
|
|
2060
2061
|
IFF(DATEDIFF(second, ds.created_at::TIMESTAMP, inf.LAST_DDL::TIMESTAMP) > 0, 'STALE', 'CURRENT') AS STATE
|
|
2061
2062
|
FROM (
|
|
2062
2063
|
SELECT (SELECT {app_name}.api.normalize_fq_ids(ARRAY_CONSTRUCT(FQ_OBJECT_NAME))[0]:identifier::string) as FQ_OBJECT_NAME,
|
|
@@ -2068,26 +2069,45 @@ Otherwise, remove it from your '{profile}' configuration profile.
|
|
|
2068
2069
|
(SELECT {app_name}.api.normalize_fq_ids(
|
|
2069
2070
|
ARRAY_CONSTRUCT(
|
|
2070
2071
|
CASE
|
|
2071
|
-
WHEN TABLE_CATALOG = UPPER(TABLE_CATALOG) THEN TABLE_CATALOG
|
|
2072
|
-
ELSE '"' || TABLE_CATALOG || '"'
|
|
2072
|
+
WHEN t.TABLE_CATALOG = UPPER(t.TABLE_CATALOG) THEN t.TABLE_CATALOG
|
|
2073
|
+
ELSE '"' || t.TABLE_CATALOG || '"'
|
|
2073
2074
|
END || '.' ||
|
|
2074
2075
|
CASE
|
|
2075
|
-
WHEN TABLE_SCHEMA = UPPER(TABLE_SCHEMA) THEN TABLE_SCHEMA
|
|
2076
|
-
ELSE '"' || TABLE_SCHEMA || '"'
|
|
2076
|
+
WHEN t.TABLE_SCHEMA = UPPER(t.TABLE_SCHEMA) THEN t.TABLE_SCHEMA
|
|
2077
|
+
ELSE '"' || t.TABLE_SCHEMA || '"'
|
|
2077
2078
|
END || '.' ||
|
|
2078
2079
|
CASE
|
|
2079
|
-
WHEN TABLE_NAME = UPPER(TABLE_NAME) THEN TABLE_NAME
|
|
2080
|
-
ELSE '"' || TABLE_NAME || '"'
|
|
2080
|
+
WHEN t.TABLE_NAME = UPPER(t.TABLE_NAME) THEN t.TABLE_NAME
|
|
2081
|
+
ELSE '"' || t.TABLE_NAME || '"'
|
|
2081
2082
|
END
|
|
2082
2083
|
)
|
|
2083
2084
|
)[0]:identifier::string) as FQN,
|
|
2084
2085
|
CONVERT_TIMEZONE('UTC', LAST_DDL) AS LAST_DDL,
|
|
2085
|
-
TABLE_TYPE as KIND
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2086
|
+
TABLE_TYPE as KIND,
|
|
2087
|
+
SHA2(LISTAGG(
|
|
2088
|
+
COLUMN_NAME ||
|
|
2089
|
+
CASE
|
|
2090
|
+
WHEN c.NUMERIC_PRECISION IS NOT NULL AND c.NUMERIC_SCALE IS NOT NULL
|
|
2091
|
+
THEN c.DATA_TYPE || '(' || c.NUMERIC_PRECISION || ',' || c.NUMERIC_SCALE || ')'
|
|
2092
|
+
WHEN c.DATETIME_PRECISION IS NOT NULL
|
|
2093
|
+
THEN c.DATA_TYPE || '(0,' || c.DATETIME_PRECISION || ')'
|
|
2094
|
+
WHEN c.CHARACTER_MAXIMUM_LENGTH IS NOT NULL
|
|
2095
|
+
THEN c.DATA_TYPE || '(' || c.CHARACTER_MAXIMUM_LENGTH || ')'
|
|
2096
|
+
ELSE c.DATA_TYPE
|
|
2097
|
+
END ||
|
|
2098
|
+
IS_NULLABLE,
|
|
2099
|
+
','
|
|
2100
|
+
) WITHIN GROUP (ORDER BY COLUMN_NAME), 256) as COLUMNS_HASH
|
|
2101
|
+
FROM {db}.INFORMATION_SCHEMA.TABLES t
|
|
2102
|
+
JOIN {db}.INFORMATION_SCHEMA.COLUMNS c
|
|
2103
|
+
ON t.TABLE_CATALOG = c.TABLE_CATALOG
|
|
2104
|
+
AND t.TABLE_SCHEMA = c.TABLE_SCHEMA
|
|
2105
|
+
AND t.TABLE_NAME = c.TABLE_NAME
|
|
2106
|
+
WHERE t.TABLE_CATALOG = {IdentityParser.to_sql_value(db)} AND ({" OR ".join(
|
|
2107
|
+
f"(t.TABLE_SCHEMA = {IdentityParser.to_sql_value(schema)} AND t.TABLE_NAME IN ({','.join(f'{IdentityParser.to_sql_value(table)}' for table in tables)}))"
|
|
2089
2108
|
for schema, tables in schemas.items()
|
|
2090
2109
|
)})
|
|
2110
|
+
GROUP BY t.TABLE_CATALOG, t.TABLE_SCHEMA, t.TABLE_NAME, t.LAST_DDL, t.TABLE_TYPE
|
|
2091
2111
|
) inf on inf.FQN = ds.FQ_OBJECT_NAME
|
|
2092
2112
|
"""
|
|
2093
2113
|
for db, schemas in partitioned_sources.items()
|
|
@@ -2102,6 +2122,7 @@ Otherwise, remove it from your '{profile}' configuration profile.
|
|
|
2102
2122
|
assert fqn, f"Error parsing returned FQN: {row_fqn}"
|
|
2103
2123
|
|
|
2104
2124
|
source_types[fqn]["type"] = "TABLE" if row["KIND"] == "BASE TABLE" else row["KIND"]
|
|
2125
|
+
source_types[fqn]["columns_hash"] = row["COLUMNS_HASH"]
|
|
2105
2126
|
source_types[fqn]["state"] = row["STATE"]
|
|
2106
2127
|
|
|
2107
2128
|
return source_types
|
|
@@ -3058,10 +3079,13 @@ class DirectAccessResources(Resources):
|
|
|
3058
3079
|
return self._retrieve_service_endpoint()
|
|
3059
3080
|
|
|
3060
3081
|
def _retrieve_service_endpoint(self, enforce_update=False) -> str:
|
|
3082
|
+
account = self.config.get("account")
|
|
3083
|
+
app_name = self.config.get("rai_app_name")
|
|
3084
|
+
service_endpoint_key = f"{account}.{app_name}.service_endpoint"
|
|
3061
3085
|
if self._service_endpoint and not enforce_update:
|
|
3062
3086
|
return self._service_endpoint
|
|
3063
|
-
if self._endpoint_info.get(
|
|
3064
|
-
self._service_endpoint = str(self._endpoint_info.get(
|
|
3087
|
+
if self._endpoint_info.get(service_endpoint_key, "") and not enforce_update:
|
|
3088
|
+
self._service_endpoint = str(self._endpoint_info.get(service_endpoint_key, ""))
|
|
3065
3089
|
return self._service_endpoint
|
|
3066
3090
|
|
|
3067
3091
|
is_snowflake_notebook = isinstance(runtime_env, SnowbookEnvironment)
|
|
@@ -3073,7 +3097,7 @@ class DirectAccessResources(Resources):
|
|
|
3073
3097
|
else:
|
|
3074
3098
|
self._service_endpoint = f"https://{result[0]['SERVICE_ENDPOINT']}"
|
|
3075
3099
|
|
|
3076
|
-
self._endpoint_info.set(
|
|
3100
|
+
self._endpoint_info.set(service_endpoint_key, self._service_endpoint)
|
|
3077
3101
|
# save the endpoint to `ENDPOINT_FILE` to avoid calling the endpoint with every
|
|
3078
3102
|
# pyrel execution
|
|
3079
3103
|
try:
|
|
@@ -3116,7 +3140,12 @@ class DirectAccessResources(Resources):
|
|
|
3116
3140
|
try:
|
|
3117
3141
|
response = _send_request()
|
|
3118
3142
|
if response.status_code != 200:
|
|
3119
|
-
|
|
3143
|
+
try:
|
|
3144
|
+
message = response.json().get("message", "")
|
|
3145
|
+
except requests.exceptions.JSONDecodeError:
|
|
3146
|
+
raise ResponseStatusException(
|
|
3147
|
+
f"Failed to parse error response from endpoint {endpoint}.", response
|
|
3148
|
+
)
|
|
3120
3149
|
|
|
3121
3150
|
# fix engine on engine error and retry
|
|
3122
3151
|
if _is_engine_issue(message):
|