omnata-plugin-runtime 0.11.0a313__py3-none-any.whl → 0.11.1__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.
@@ -470,10 +470,20 @@ class SnowflakeViewPart(BaseModel):
470
470
  c.name_with_comment(binding_list) for c in self.columns
471
471
  ]
472
472
 
473
- def cte_text(self,original_name: bool = False, include_only_columns:Optional[List[str]] = None) -> str:
473
+ def cte_text(self,original_name: bool = False,
474
+ include_only_columns:Optional[List[str]] = None,
475
+ include_extra_columns:Optional[List[str]] = None
476
+ ) -> str:
474
477
  """
475
478
  Returns the CTE text for this view part.
476
479
  """
480
+ if include_extra_columns is not None:
481
+ # includes direct columns plus any extra specified
482
+ return f""" "{self.stream_name}" as (
483
+ select {', '.join([c.definition(original_name=original_name,remove_stream_prefix=self.stream_name) for c in self.columns
484
+ if c.original_name in include_extra_columns or not c.is_join_column])}
485
+ from {self.raw_table_location.get_fully_qualified_name()}
486
+ ) """
477
487
  if include_only_columns is None:
478
488
  return f""" "{self.stream_name}" as (
479
489
  select {', '.join([c.definition(original_name=original_name,remove_stream_prefix=self.stream_name) for c in self.direct_columns()])}
@@ -504,6 +514,29 @@ class SnowflakeViewParts(BaseModel):
504
514
  ..., description="The other streams that are joined to the main stream"
505
515
  )
506
516
 
517
+ def column_indirectly_references_other_streams(
518
+ self,
519
+ all_view_parts:List[SnowflakeViewPart],
520
+ stream_name:str,column_name:str) -> bool:
521
+
522
+ for part in all_view_parts:
523
+ if part.stream_name == stream_name:
524
+ for col in part.columns:
525
+ if col.original_name == column_name:
526
+ if col.referenced_columns:
527
+ for ref_stream, ref_cols in col.referenced_columns.items():
528
+ if ref_stream != stream_name:
529
+ return True
530
+ else:
531
+ # we have to call this recursively in case the referenced column also references other streams
532
+ result = any(
533
+ self.column_indirectly_references_other_streams(
534
+ all_view_parts, ref_stream, ref_col
535
+ ) for ref_col in ref_cols
536
+ )
537
+ return result
538
+ return False
539
+
507
540
  def view_body(self):
508
541
  """
509
542
  Creates a view definition from the parts.
@@ -519,31 +552,44 @@ class SnowflakeViewParts(BaseModel):
519
552
 
520
553
  # first, we need to collapse all referenced columns into a single map
521
554
  all_referenced_columns:Dict[str,List[str]] = {}
555
+
556
+ # if a column references other columns, but there are no dependencies outside of its own stream, we can include those columns in the initial CTE for that stream
557
+ # because they can be calculated directly without needing joins
558
+ columns_only_referencing_own_stream:Dict[str,List[str]] = {}
559
+
522
560
  for part in [self.main_part] + self.joined_parts:
523
- # if the main part references any columns in this part in its joins, we need to include those columns
561
+ # if the main part references any columns in this part in its joins, we need to include those columns because they are used in the join condition
524
562
  aliases_for_stream = [j.join_stream_alias for j in self.main_part.joins
525
563
  if j.join_stream_name == part.stream_name]
526
564
  columns_used_in_joins = [
527
565
  j.left_column for j in self.main_part.joins if j.left_alias in aliases_for_stream
528
566
  ]
529
- if part.stream_name not in all_referenced_columns:
530
- all_referenced_columns[part.stream_name] = []
531
- all_referenced_columns[part.stream_name] += columns_used_in_joins
567
+ all_referenced_columns.setdefault(part.stream_name, []).extend(columns_used_in_joins)
568
+ # now, for each column in the part, if it references columns in other streams, we need to include those columns
532
569
  for column in part.columns:
533
570
  if column.referenced_columns:
534
571
  for stream_name, referenced_columns in column.referenced_columns.items():
535
- if stream_name not in all_referenced_columns:
536
- all_referenced_columns[stream_name] = []
537
- all_referenced_columns[stream_name] += referenced_columns
572
+ aliases_for_referenced_stream = [j.join_stream_name for j in self.main_part.joins
573
+ if j.join_stream_alias == stream_name]
574
+ all_referenced_columns.setdefault(stream_name, []).extend(referenced_columns)
575
+ # the stream name could be an alias, so we need to check if it's one of the aliases for this part
576
+ for stream_name_for_alias in aliases_for_referenced_stream:
577
+ all_referenced_columns.setdefault(stream_name_for_alias, []).extend(referenced_columns)
578
+ # populate columns_only_referencing_own_stream by following the chain of references until we reach a column that references another stream or has no references
579
+ if self.column_indirectly_references_other_streams(
580
+ [self.main_part] + self.joined_parts, part.stream_name, column.original_name
581
+ ) == False:
582
+ columns_only_referencing_own_stream.setdefault(part.stream_name, []).append(column.original_name)
583
+ else:
584
+ # if the column has no references, it can be included in the initial CTE for its own stream
585
+ columns_only_referencing_own_stream.setdefault(part.stream_name, []).append(column.original_name)
586
+ # if this part has joins to other streams, we need to include the join columns
538
587
  for join in part.joins:
539
- if join.join_stream_name not in all_referenced_columns:
540
- all_referenced_columns[join.join_stream_name] = []
541
- all_referenced_columns[join.join_stream_name].append(join.join_stream_column)
542
- all_referenced_columns[part.stream_name].append(join.left_column)
543
-
544
-
588
+ all_referenced_columns.setdefault(join.join_stream_name, []).append(join.join_stream_column)
589
+ all_referenced_columns.setdefault(join.join_stream_alias, []).append(join.join_stream_column)
590
+ all_referenced_columns.setdefault(part.stream_name, []).append(join.left_column)
545
591
  ctes = [
546
- self.main_part.cte_text(original_name=True)
592
+ self.main_part.cte_text(original_name=True,include_extra_columns=columns_only_referencing_own_stream.get(self.main_part.stream_name))
547
593
  ] + [
548
594
  part.cte_text(original_name=True,include_only_columns=all_referenced_columns.get(part.stream_name))
549
595
  for part in joined_parts_deduped
@@ -553,9 +599,9 @@ class SnowflakeViewParts(BaseModel):
553
599
  final_cte = f""" OMNATA_FINAL_CTE as (
554
600
  select {', '.join(
555
601
  [
556
- f'"{self.main_part.stream_name}"."{c.original_name}"' for c in self.main_part.direct_columns()
602
+ f'"{self.main_part.stream_name}"."{c.original_name}"' for c in self.main_part.columns if not c.is_join_column or c.original_name in columns_only_referencing_own_stream.get(self.main_part.stream_name,[])
557
603
  ]+[
558
- c.definition(original_name=True) for c in self.main_part.join_columns()
604
+ c.definition(original_name=True) for c in self.main_part.columns if c.is_join_column and c.original_name not in columns_only_referencing_own_stream.get(self.main_part.stream_name,[])
559
605
  ])}
560
606
  from "{self.main_part.stream_name}" """
561
607
  if len(self.main_part.joins) > 0:
@@ -761,6 +807,25 @@ class SnowflakeViewParts(BaseModel):
761
807
 
762
808
  return cls(main_part=main_stream_view_part, joined_parts=joined_parts)
763
809
 
810
+
811
+ # Helper function to find a view part by stream name
812
+ def find_part(view_part: SnowflakeViewPart, joined_parts: List[SnowflakeViewPart], stream_name: str) -> Optional[SnowflakeViewPart]:
813
+ if stream_name == view_part.stream_name:
814
+ return view_part
815
+ for part in joined_parts:
816
+ if part.stream_name == stream_name:
817
+ return part
818
+ for join in view_part.joins:
819
+ if join.join_stream_alias == stream_name:
820
+ # this is the join, we need to find the actual stream
821
+ for part in joined_parts:
822
+ if part.stream_name == join.join_stream_name:
823
+ return part
824
+ logger.warning(
825
+ f"Join alias {stream_name} maps to stream {join.join_stream_name}, but that stream is not in the joined parts"
826
+ )
827
+ return None
828
+
764
829
  def prune(view_part: SnowflakeViewPart, joined_parts: List[SnowflakeViewPart]) -> bool:
765
830
  """
766
831
  Prunes columns from view parts that reference fields that don't exist in the referenced streams.
@@ -773,12 +838,6 @@ def prune(view_part: SnowflakeViewPart, joined_parts: List[SnowflakeViewPart]) -
773
838
  Raises ValueError if a cyclic dependency is detected.
774
839
  """
775
840
  columns_removed = False
776
-
777
- # Helper function to find a view part by stream name
778
- def find_part(stream_name: str) -> Optional[SnowflakeViewPart]:
779
- if stream_name == view_part.stream_name:
780
- return view_part
781
- return next((p for p in joined_parts if p.stream_name == stream_name), None)
782
841
 
783
842
  # Helper function to check if a column should be kept or removed
784
843
  def should_keep_column(column: SnowflakeViewColumn, part: SnowflakeViewPart) -> bool:
@@ -793,7 +852,7 @@ def prune(view_part: SnowflakeViewPart, joined_parts: List[SnowflakeViewPart]) -
793
852
  # Check each referenced stream and its fields
794
853
  for ref_stream_name, ref_fields in column.referenced_columns.items():
795
854
  # Find the referenced part
796
- ref_part = find_part(ref_stream_name)
855
+ ref_part = find_part(view_part, joined_parts,ref_stream_name)
797
856
 
798
857
  # If referenced stream doesn't exist, remove the column
799
858
  if ref_part is None:
@@ -1,7 +1,8 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: omnata-plugin-runtime
3
- Version: 0.11.0a313
3
+ Version: 0.11.1
4
4
  Summary: Classes and common runtime components for building and running Omnata Plugins
5
+ License-File: LICENSE
5
6
  Author: James Weakley
6
7
  Author-email: james.weakley@omnata.com
7
8
  Requires-Python: >=3.8,<=3.11
@@ -2,12 +2,12 @@ omnata_plugin_runtime/__init__.py,sha256=MS9d1whnfT_B3-ThqZ7l63QeC_8OEKTuaYV5wTw
2
2
  omnata_plugin_runtime/api.py,sha256=5gbjbnFy72Xjf0E3kbG23G0V2J3CorvD5kpBn_BkdlI,8084
3
3
  omnata_plugin_runtime/configuration.py,sha256=SffokJfgvy6V3kUsoEjXcK3GdNgHo6U3mgBEs0qBv4I,46972
4
4
  omnata_plugin_runtime/forms.py,sha256=Lrbr3otsFDrvHWJw7v-slsW4PvEHJ6BG1Yl8oaJfiDo,20529
5
- omnata_plugin_runtime/json_schema.py,sha256=xI5YeoxdV1e4fYLUYB-1ZGXZrLAIrSnKj91189wf8cQ,49943
5
+ omnata_plugin_runtime/json_schema.py,sha256=_3oLravvrbIM8dy-bOZSON22Di1FvNnDAsiehwfoH-E,54125
6
6
  omnata_plugin_runtime/logging.py,sha256=WBuZt8lF9E5oFWM4KYQbE8dDJ_HctJ1pN3BHwU6rcd0,4461
7
7
  omnata_plugin_runtime/omnata_plugin.py,sha256=PV1BzsqI2yi3pd6DBSRc1s1QJ_My-b6pewrB7ad4sms,140256
8
8
  omnata_plugin_runtime/plugin_entrypoints.py,sha256=_1pDLov3iQorGmfcae8Sw2bVjxw1vYeowBaKKNzRclQ,32629
9
9
  omnata_plugin_runtime/rate_limiting.py,sha256=qpr5esU4Ks8hMzuMpSR3gLFdor2ZUXYWCjmsQH_K6lQ,25882
10
- omnata_plugin_runtime-0.11.0a313.dist-info/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
11
- omnata_plugin_runtime-0.11.0a313.dist-info/METADATA,sha256=cKUI7DscZ7fka1sfOEUJ0T9p3usHMohmiuBc9TPVM-E,2211
12
- omnata_plugin_runtime-0.11.0a313.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
13
- omnata_plugin_runtime-0.11.0a313.dist-info/RECORD,,
10
+ omnata_plugin_runtime-0.11.1.dist-info/METADATA,sha256=d040ESGm3ElaDUf4pdLsIsXE21J5h2xuwDHwbpnbrNg,2229
11
+ omnata_plugin_runtime-0.11.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
12
+ omnata_plugin_runtime-0.11.1.dist-info/licenses/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
13
+ omnata_plugin_runtime-0.11.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any