pylegend 0.8.0__tar.gz → 0.9.0__tar.gz

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.
Files changed (173) hide show
  1. {pylegend-0.8.0 → pylegend-0.9.0}/PKG-INFO +1 -1
  2. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/_typing.py +6 -0
  3. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/database/sql_to_string/db_extension.py +35 -6
  4. pylegend-0.9.0/pylegend/core/language/pandas_api/pandas_api_aggregate_specification.py +54 -0
  5. pylegend-0.9.0/pylegend/core/language/pandas_api/pandas_api_custom_expressions.py +85 -0
  6. pylegend-0.9.0/pylegend/core/language/pandas_api/pandas_api_series.py +174 -0
  7. pylegend-0.9.0/pylegend/core/language/pandas_api/pandas_api_tds_row.py +74 -0
  8. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/integer_operation_expressions.py +35 -0
  9. pylegend-0.9.0/pylegend/core/language/shared/operations/nary_expression.py +104 -0
  10. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/primitive_operation_expressions.py +30 -0
  11. pylegend-0.9.0/pylegend/core/language/shared/operations/string_operation_expressions.py +1176 -0
  12. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/integer.py +6 -0
  13. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/primitive.py +6 -0
  14. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/string.py +129 -1
  15. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/sql/metamodel.py +3 -1
  16. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/sql/metamodel_extension.py +18 -0
  17. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/aggregate_function.py +316 -0
  18. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/frames/functions/assign_function.py +20 -15
  19. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/drop.py +171 -0
  20. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/filter.py +193 -0
  21. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/filtering.py +85 -0
  22. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/sort_values_function.py +189 -0
  23. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/functions/truncate_function.py +120 -0
  24. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/frames/pandas_api_applied_function_tds_frame.py +5 -1
  25. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +348 -0
  26. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/frames/pandas_api_input_tds_frame.py +5 -3
  27. pylegend-0.9.0/pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +130 -0
  28. pylegend-0.9.0/pylegend/extensions/tds/legendql_api/frames/__init__.py +13 -0
  29. {pylegend-0.8.0 → pylegend-0.9.0}/pyproject.toml +5 -2
  30. pylegend-0.8.0/pylegend/core/language/shared/operations/string_operation_expressions.py +0 -553
  31. pylegend-0.8.0/pylegend/core/tds/pandas_api/frames/pandas_api_base_tds_frame.py +0 -151
  32. pylegend-0.8.0/pylegend/core/tds/pandas_api/frames/pandas_api_tds_frame.py +0 -43
  33. {pylegend-0.8.0 → pylegend-0.9.0}/LICENSE +0 -0
  34. {pylegend-0.8.0 → pylegend-0.9.0}/LICENSE.spdx +0 -0
  35. {pylegend-0.8.0 → pylegend-0.9.0}/NOTICE +0 -0
  36. {pylegend-0.8.0 → pylegend-0.9.0}/README.md +0 -0
  37. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/__init__.py +0 -0
  38. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/__init__.py +0 -0
  39. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/database/__init__.py +0 -0
  40. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/database/sql_to_string/__init__.py +0 -0
  41. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/database/sql_to_string/config.py +0 -0
  42. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/database/sql_to_string/generator.py +0 -0
  43. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/__init__.py +0 -0
  44. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legacy_api/__init__.py +0 -0
  45. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legacy_api/aggregate_specification.py +0 -0
  46. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legacy_api/legacy_api_tds_row.py +0 -0
  47. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legendql_api/__init__.py +0 -0
  48. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legendql_api/legendql_api_custom_expressions.py +0 -0
  49. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/legendql_api/legendql_api_tds_row.py +0 -0
  50. {pylegend-0.8.0/pylegend/core/language/shared → pylegend-0.9.0/pylegend/core/language/pandas_api}/__init__.py +0 -0
  51. {pylegend-0.8.0/pylegend/core/tds/abstract → pylegend-0.9.0/pylegend/core/language/shared}/__init__.py +0 -0
  52. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/column_expressions.py +0 -0
  53. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/expression.py +0 -0
  54. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/functions.py +0 -0
  55. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/helpers.py +0 -0
  56. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/literal_expressions.py +0 -0
  57. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/__init__.py +0 -0
  58. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/binary_expression.py +0 -0
  59. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/boolean_operation_expressions.py +0 -0
  60. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/collection_operation_expressions.py +0 -0
  61. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/date_operation_expressions.py +0 -0
  62. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/float_operation_expressions.py +0 -0
  63. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/nullary_expression.py +0 -0
  64. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/number_operation_expressions.py +0 -0
  65. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/operations/unary_expression.py +0 -0
  66. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/pct_helpers.py +0 -0
  67. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitive_collection.py +0 -0
  68. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/__init__.py +0 -0
  69. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/boolean.py +0 -0
  70. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/date.py +0 -0
  71. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/datetime.py +0 -0
  72. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/float.py +0 -0
  73. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/number.py +0 -0
  74. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/primitives/strictdate.py +0 -0
  75. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/language/shared/tds_row.py +0 -0
  76. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/project_cooridnates.py +0 -0
  77. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/request/__init__.py +0 -0
  78. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/request/auth.py +0 -0
  79. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/request/legend_client.py +0 -0
  80. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/request/response_reader.py +0 -0
  81. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/request/service_client.py +0 -0
  82. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/sql/__init__.py +0 -0
  83. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/__init__.py +0 -0
  84. {pylegend-0.8.0/pylegend/core/tds/abstract/frames → pylegend-0.9.0/pylegend/core/tds/abstract}/__init__.py +0 -0
  85. {pylegend-0.8.0/pylegend/core/tds/legendql_api → pylegend-0.9.0/pylegend/core/tds/abstract/frames}/__init__.py +0 -0
  86. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/abstract/frames/applied_function_tds_frame.py +0 -0
  87. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/abstract/frames/base_tds_frame.py +0 -0
  88. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/abstract/frames/input_tds_frame.py +0 -0
  89. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/abstract/function_helpers.py +0 -0
  90. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/__init__.py +0 -0
  91. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/__init__.py +0 -0
  92. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/__init__.py +0 -0
  93. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_concatenate_function.py +0 -0
  94. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_distinct_function.py +0 -0
  95. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_drop_function.py +0 -0
  96. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_extend_function.py +0 -0
  97. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_filter_function.py +0 -0
  98. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_group_by_function.py +0 -0
  99. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_head_function.py +0 -0
  100. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_join_by_columns_function.py +0 -0
  101. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_join_function.py +0 -0
  102. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_rename_columns_function.py +0 -0
  103. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_restrict_function.py +0 -0
  104. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_slice_function.py +0 -0
  105. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/functions/legacy_api_sort_function.py +0 -0
  106. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/legacy_api_applied_function_tds_frame.py +0 -0
  107. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/legacy_api_base_tds_frame.py +0 -0
  108. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/legacy_api_input_tds_frame.py +0 -0
  109. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legacy_api/frames/legacy_api_tds_frame.py +0 -0
  110. {pylegend-0.8.0/pylegend/core/tds/legendql_api/frames → pylegend-0.9.0/pylegend/core/tds/legendql_api}/__init__.py +0 -0
  111. {pylegend-0.8.0/pylegend/core/tds/legendql_api/frames/functions → pylegend-0.9.0/pylegend/core/tds/legendql_api/frames}/__init__.py +0 -0
  112. {pylegend-0.8.0/pylegend/extensions/tds/legendql_api → pylegend-0.9.0/pylegend/core/tds/legendql_api/frames/functions}/__init__.py +0 -0
  113. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_asofjoin_function.py +0 -0
  114. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_concatenate_function.py +0 -0
  115. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_distinct_function.py +0 -0
  116. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_drop_function.py +0 -0
  117. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_extend_function.py +0 -0
  118. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_filter_function.py +0 -0
  119. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_function_helpers.py +0 -0
  120. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_groupby_function.py +0 -0
  121. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_head_function.py +0 -0
  122. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_join_function.py +0 -0
  123. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_project_function.py +0 -0
  124. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_rename_function.py +0 -0
  125. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_select_function.py +0 -0
  126. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_slice_function.py +0 -0
  127. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_sort_function.py +0 -0
  128. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/functions/legendql_api_window_extend_function.py +0 -0
  129. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/legendql_api_applied_function_tds_frame.py +0 -0
  130. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/legendql_api_base_tds_frame.py +0 -0
  131. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/legendql_api_input_tds_frame.py +0 -0
  132. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/legendql_api/frames/legendql_api_tds_frame.py +0 -0
  133. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/__init__.py +0 -0
  134. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/frames/__init__.py +0 -0
  135. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/pandas_api/frames/functions/__init__.py +0 -0
  136. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/result_handler/__init__.py +0 -0
  137. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/result_handler/result_handler.py +0 -0
  138. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/result_handler/to_csv_file_result_handler.py +0 -0
  139. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/result_handler/to_json_file_result_handler.py +0 -0
  140. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/result_handler/to_string_result_handler.py +0 -0
  141. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/sql_query_helpers.py +0 -0
  142. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/tds_column.py +0 -0
  143. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/core/tds/tds_frame.py +0 -0
  144. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/__init__.py +0 -0
  145. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/database/__init__.py +0 -0
  146. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/database/vendors/__init__.py +0 -0
  147. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/database/vendors/postgres/__init__.py +0 -0
  148. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/database/vendors/postgres/postgres_sql_to_string.py +0 -0
  149. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/__init__.py +0 -0
  150. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/abstract/__init__.py +0 -0
  151. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/abstract/legend_function_input_frame.py +0 -0
  152. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/abstract/legend_service_input_frame.py +0 -0
  153. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/abstract/table_spec_input_frame.py +0 -0
  154. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legacy_api/__init__.py +0 -0
  155. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legacy_api/frames/__init__.py +0 -0
  156. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_legend_function_input_frame.py +0 -0
  157. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_legend_service_input_frame.py +0 -0
  158. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legacy_api/frames/legacy_api_table_spec_input_frame.py +0 -0
  159. {pylegend-0.8.0/pylegend/extensions/tds/legendql_api/frames → pylegend-0.9.0/pylegend/extensions/tds/legendql_api}/__init__.py +0 -0
  160. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_function_input_frame.py +0 -0
  161. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_legend_service_input_frame.py +0 -0
  162. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/legendql_api/frames/legendql_api_table_spec_input_frame.py +0 -0
  163. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/pandas_api/__init__.py +0 -0
  164. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/pandas_api/frames/__init__.py +0 -0
  165. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_function_input_frame.py +0 -0
  166. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_legend_service_input_frame.py +0 -0
  167. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/pandas_api/frames/pandas_api_table_spec_input_frame.py +0 -0
  168. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/result_handler/__init__.py +0 -0
  169. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/extensions/tds/result_handler/to_pandas_df_result_handler.py +0 -0
  170. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/legacy_api_tds_client.py +0 -0
  171. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/legendql_api_tds_client.py +0 -0
  172. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/utils/__init__.py +0 -0
  173. {pylegend-0.8.0 → pylegend-0.9.0}/pylegend/utils/class_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pylegend
3
- Version: 0.8.0
3
+ Version: 0.9.0
4
4
  Summary: Python language binding for Legend data management platform
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -16,6 +16,7 @@ from typing import Callable as PyLegendCallable
16
16
  from typing import Dict as PyLegendDict
17
17
  from typing import Iterator as PyLegendIterator
18
18
  from typing import List as PyLegendList
19
+ from typing import Set as PyLegendSet
19
20
  from typing import Optional as PyLegendOptional
20
21
  from typing import Sequence as PyLegendSequence
21
22
  from typing import Type as PyLegendType
@@ -24,6 +25,8 @@ from typing import Tuple as PyLegendTuple
24
25
  from typing import Generator as PyLegendGenerator
25
26
  from typing import Union as PyLegendUnion
26
27
  from typing import Generic as PyLegendGeneric
28
+ from typing import Hashable as PyLegendHashable
29
+ from typing import Mapping as PyLegendMapping
27
30
  from typing import TYPE_CHECKING
28
31
 
29
32
 
@@ -32,6 +35,7 @@ __all__: PyLegendSequence[str] = [
32
35
  "PyLegendDict",
33
36
  "PyLegendIterator",
34
37
  "PyLegendList",
38
+ "PyLegendSet",
35
39
  "PyLegendSequence",
36
40
  "PyLegendType",
37
41
  "PyLegendTypeVar",
@@ -40,5 +44,7 @@ __all__: PyLegendSequence[str] = [
40
44
  "PyLegendGenerator",
41
45
  "PyLegendUnion",
42
46
  "PyLegendGeneric",
47
+ "PyLegendMapping",
48
+ "PyLegendHashable",
43
49
  "TYPE_CHECKING",
44
50
  ]
@@ -132,9 +132,9 @@ from pylegend.core.sql.metamodel_extension import (
132
132
  EpochExpression,
133
133
  WindowExpression,
134
134
  ConstantExpression,
135
+ StringSubStringExpression,
135
136
  )
136
137
 
137
-
138
138
  __all__: PyLegendSequence[str] = [
139
139
  "SqlToStringDbExtension"
140
140
  ]
@@ -454,6 +454,8 @@ def expression_processor(
454
454
  return extension.process_window_expression(expression, config)
455
455
  elif isinstance(expression, ConstantExpression):
456
456
  return expression.name
457
+ elif isinstance(expression, StringSubStringExpression):
458
+ return extension.process_string_substring_expression(expression, config)
457
459
 
458
460
  else:
459
461
  raise ValueError("Unsupported expression type: " + str(type(expression))) # pragma: no cover
@@ -484,6 +486,10 @@ def comparison_expression_processor(
484
486
  cmp = "<"
485
487
  elif comparison.operator == ComparisonOperator.LESS_THAN_OR_EQUAL:
486
488
  cmp = "<="
489
+ elif comparison.operator == ComparisonOperator.REGEX_MATCH:
490
+ cmp = "~"
491
+ elif comparison.operator == ComparisonOperator.LIKE:
492
+ cmp = "~~"
487
493
  else:
488
494
  raise ValueError("Unknown comparison operator type: " + str(comparison.operator)) # pragma: no cover
489
495
 
@@ -674,18 +680,32 @@ def function_call_processor(
674
680
  ) -> str:
675
681
  # TODO: Handle distinct and filter
676
682
 
677
- arguments = ("," + config.format.separator(1)).join(
678
- [extension.process_expression(arg, config.push_indent()) for arg in function_call.arguments]
683
+ formatted_args = [
684
+ extension.process_expression(arg, config.push_indent())
685
+ for arg in function_call.arguments
686
+ ]
687
+
688
+ total_args_length = sum(len(arg) for arg in formatted_args)
689
+
690
+ requires_multiline = (
691
+ any("\n" in arg or len(arg) > 80 for arg in formatted_args)
692
+ or total_args_length > 80
679
693
  )
680
694
 
695
+ arguments = (
696
+ "," + (config.format.separator(1) if requires_multiline else " ")
697
+ ).join(formatted_args)
698
+
681
699
  window = ""
682
700
  if function_call.window:
683
701
  window = " " + extension.process_window(function_call.window, config)
684
702
 
685
- first_sep = config.format.separator(1) if function_call.arguments else ""
686
- sep0 = config.format.separator(0) if function_call.arguments else ""
687
703
  name = extension.process_qualified_name(function_call.name, config)
688
- return f"{name}({first_sep}{arguments}{sep0}){window}"
704
+
705
+ if not requires_multiline:
706
+ return f"{name}({arguments}){window}"
707
+ else:
708
+ return f"{name}({config.format.separator(1)}{arguments}{config.format.separator(0)}){window}"
689
709
 
690
710
 
691
711
  def named_argument_processor(
@@ -1009,6 +1029,15 @@ class SqlToStringDbExtension:
1009
1029
  def process_string_pos_expression(self, expr: StringPosExpression, config: SqlToStringConfig) -> str:
1010
1030
  return f"STRPOS({self.process_expression(expr.value, config)}, {self.process_expression(expr.other, config)})"
1011
1031
 
1032
+ def process_string_substring_expression(self, expr: StringSubStringExpression, config: SqlToStringConfig) -> str:
1033
+ value = self.process_expression(expr.value, config)
1034
+ start = self.process_expression(expr.start, config)
1035
+ return (
1036
+ f"SUBSTR({value}, ({start}) + 1)"
1037
+ if expr.end is None
1038
+ else f"SUBSTR({value}, ({start}) + 1, ({self.process_expression(expr.end, config)}) - ({start}) + 1)"
1039
+ )
1040
+
1012
1041
  def process_string_concat_expression(self, expr: StringConcatExpression, config: SqlToStringConfig) -> str:
1013
1042
  return f"CONCAT({self.process_expression(expr.first, config)}, {self.process_expression(expr.second, config)})"
1014
1043
 
@@ -0,0 +1,54 @@
1
+ # Copyright 2025 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import numpy as np
16
+ from pylegend._typing import (
17
+ PyLegendSequence,
18
+ PyLegendUnion,
19
+ PyLegendList,
20
+ PyLegendCallable,
21
+ PyLegendMapping,
22
+ PyLegendHashable,
23
+ )
24
+ from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitiveOrPythonPrimitive
25
+
26
+ __all__: PyLegendSequence[str] = [
27
+ "PyLegendAggFunc",
28
+ "PyLegendAggList",
29
+ "PyLegendAggDict",
30
+ "PyLegendAggInput",
31
+ ]
32
+
33
+
34
+ PyLegendAggFunc = PyLegendUnion[ # type: ignore[explicit-any]
35
+ PyLegendCallable[..., PyLegendPrimitiveOrPythonPrimitive],
36
+ str,
37
+ np.ufunc,
38
+ ]
39
+
40
+ PyLegendAggList = PyLegendList[PyLegendAggFunc]
41
+
42
+ PyLegendAggDict = PyLegendMapping[
43
+ PyLegendHashable,
44
+ PyLegendUnion[
45
+ PyLegendAggFunc,
46
+ PyLegendAggList
47
+ ]
48
+ ]
49
+
50
+ PyLegendAggInput = PyLegendUnion[
51
+ PyLegendAggFunc,
52
+ PyLegendAggList,
53
+ PyLegendAggDict,
54
+ ]
@@ -0,0 +1,85 @@
1
+ # Copyright 2025 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from abc import ABCMeta
16
+ from pylegend.core.language import (
17
+ PyLegendPrimitive,
18
+ PyLegendBoolean,
19
+ PyLegendString,
20
+ PyLegendNumber,
21
+ PyLegendInteger,
22
+ PyLegendFloat,
23
+ PyLegendDate,
24
+ PyLegendDateTime,
25
+ PyLegendStrictDate,
26
+ )
27
+ from pylegend._typing import (
28
+ PyLegendSequence,
29
+ )
30
+
31
+ __all__: PyLegendSequence[str] = [
32
+ "PandasApiPrimitive",
33
+ "PandasApiBoolean",
34
+ "PandasApiString",
35
+ "PandasApiNumber",
36
+ "PandasApiInteger",
37
+ "PandasApiFloat",
38
+ "PandasApiDate",
39
+ "PandasApiDateTime",
40
+ "PandasApiStrictDate",
41
+ ]
42
+
43
+
44
+ class PandasApiPrimitive(PyLegendPrimitive, metaclass=ABCMeta):
45
+ pass
46
+
47
+
48
+ class PandasApiBoolean(PandasApiPrimitive, PyLegendBoolean):
49
+ def __init__(self, expr: PyLegendBoolean):
50
+ PyLegendBoolean.__init__(self, expr.value())
51
+
52
+
53
+ class PandasApiString(PandasApiPrimitive, PyLegendString):
54
+ def __init__(self, expr: PyLegendString):
55
+ PyLegendString.__init__(self, expr.value())
56
+
57
+
58
+ class PandasApiNumber(PandasApiPrimitive, PyLegendNumber):
59
+ def __init__(self, expr: PyLegendNumber):
60
+ PyLegendNumber.__init__(self, expr.value())
61
+
62
+
63
+ class PandasApiInteger(PandasApiPrimitive, PyLegendInteger):
64
+ def __init__(self, expr: PyLegendInteger):
65
+ PyLegendInteger.__init__(self, expr.value())
66
+
67
+
68
+ class PandasApiFloat(PandasApiPrimitive, PyLegendFloat):
69
+ def __init__(self, expr: PyLegendFloat):
70
+ PyLegendFloat.__init__(self, expr.value())
71
+
72
+
73
+ class PandasApiDate(PandasApiPrimitive, PyLegendDate):
74
+ def __init__(self, expr: PyLegendDate):
75
+ PyLegendDate.__init__(self, expr.value())
76
+
77
+
78
+ class PandasApiDateTime(PandasApiPrimitive, PyLegendDateTime):
79
+ def __init__(self, expr: PyLegendDateTime):
80
+ PyLegendDateTime.__init__(self, expr.value())
81
+
82
+
83
+ class PandasApiStrictDate(PandasApiPrimitive, PyLegendStrictDate):
84
+ def __init__(self, expr: PyLegendStrictDate):
85
+ PyLegendStrictDate.__init__(self, expr.value())
@@ -0,0 +1,174 @@
1
+ # Copyright 2025 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from typing import TYPE_CHECKING
16
+
17
+ import pandas as pd
18
+
19
+ from pylegend._typing import (
20
+ PyLegendDict,
21
+ )
22
+ from pylegend._typing import (
23
+ PyLegendSequence,
24
+ PyLegendOptional,
25
+ PyLegendTypeVar
26
+ )
27
+ from pylegend.core.language.pandas_api.pandas_api_tds_row import PandasApiTdsRow
28
+ from pylegend.core.language.shared.column_expressions import PyLegendColumnExpression
29
+ from pylegend.core.language.shared.expression import (
30
+ PyLegendExpressionBooleanReturn,
31
+ PyLegendExpressionStringReturn,
32
+ PyLegendExpressionNumberReturn,
33
+ PyLegendExpressionIntegerReturn,
34
+ PyLegendExpressionFloatReturn,
35
+ PyLegendExpressionDateReturn,
36
+ PyLegendExpressionDateTimeReturn,
37
+ PyLegendExpressionStrictDateReturn,
38
+ )
39
+ from pylegend.core.language.shared.primitives.boolean import PyLegendBoolean
40
+ from pylegend.core.language.shared.primitives.date import PyLegendDate
41
+ from pylegend.core.language.shared.primitives.datetime import PyLegendDateTime
42
+ from pylegend.core.language.shared.primitives.float import PyLegendFloat
43
+ from pylegend.core.language.shared.primitives.integer import PyLegendInteger
44
+ from pylegend.core.language.shared.primitives.number import PyLegendNumber
45
+ from pylegend.core.language.shared.primitives.primitive import PyLegendPrimitive
46
+ from pylegend.core.language.shared.primitives.strictdate import PyLegendStrictDate
47
+ from pylegend.core.language.shared.primitives.string import PyLegendString
48
+ from pylegend.core.sql.metamodel import (
49
+ Expression,
50
+ )
51
+ from pylegend.core.sql.metamodel import QuerySpecification
52
+ from pylegend.core.tds.abstract.frames.base_tds_frame import BaseTdsFrame
53
+ from pylegend.core.tds.result_handler import ResultHandler
54
+ from pylegend.core.tds.tds_column import TdsColumn
55
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
56
+ from pylegend.core.tds.tds_frame import FrameToSqlConfig
57
+ from pylegend.extensions.tds.result_handler import PandasDfReadConfig
58
+
59
+ if TYPE_CHECKING:
60
+ from pylegend.core.tds.pandas_api.frames.pandas_api_tds_frame import PandasApiTdsFrame
61
+
62
+ __all__: PyLegendSequence[str] = [
63
+ "Series"
64
+ ]
65
+
66
+ R = PyLegendTypeVar('R')
67
+
68
+
69
+ class Series(PyLegendColumnExpression, PyLegendPrimitive, BaseTdsFrame):
70
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
71
+ row = PandasApiTdsRow.from_tds_frame("c", base_frame)
72
+ PyLegendColumnExpression.__init__(self, row=row, column=column)
73
+
74
+ self.__base_frame = base_frame
75
+ self._filtered_frame = base_frame.filter(items=[column])
76
+
77
+ def value(self) -> PyLegendColumnExpression:
78
+ return self
79
+
80
+ def to_sql_expression(
81
+ self,
82
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
83
+ config: FrameToSqlConfig
84
+ ) -> Expression:
85
+ return super().to_sql_expression(frame_name_to_base_query_map, config)
86
+
87
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
88
+ return super().to_pure_expression(config)
89
+
90
+ def columns(self) -> PyLegendSequence[TdsColumn]:
91
+ return self._filtered_frame.columns()
92
+
93
+ def to_sql_query(self, config: FrameToSqlConfig = FrameToSqlConfig()) -> str:
94
+ return self._filtered_frame.to_sql_query(config)
95
+
96
+ def to_pure_query(self, config: FrameToPureConfig = FrameToPureConfig()) -> str:
97
+ return self._filtered_frame.to_pure_query(config)
98
+
99
+ def execute_frame(
100
+ self,
101
+ result_handler: ResultHandler[R],
102
+ chunk_size: PyLegendOptional[int] = None
103
+ ) -> R:
104
+ return self._filtered_frame.execute_frame(result_handler, chunk_size) # pragma: no cover
105
+
106
+ def execute_frame_to_string(
107
+ self,
108
+ chunk_size: PyLegendOptional[int] = None
109
+ ) -> str:
110
+ return self._filtered_frame.execute_frame_to_string(chunk_size)
111
+
112
+ def execute_frame_to_pandas_df(
113
+ self,
114
+ chunk_size: PyLegendOptional[int] = None,
115
+ pandas_df_read_config: PandasDfReadConfig = PandasDfReadConfig()
116
+ ) -> pd.DataFrame:
117
+ return self._filtered_frame.execute_frame_to_pandas_df(chunk_size, pandas_df_read_config) # pragma: no cover
118
+
119
+ def to_sql_query_object(self, config: FrameToSqlConfig) -> QuerySpecification:
120
+ return self._filtered_frame.to_sql_query_object(config) # type: ignore
121
+
122
+ def to_pure(self, config: FrameToPureConfig) -> str:
123
+ return self._filtered_frame.to_pure(config) # type: ignore
124
+
125
+ def get_all_tds_frames(self) -> PyLegendSequence["BaseTdsFrame"]:
126
+ return self._filtered_frame.get_all_tds_frames() # type: ignore
127
+
128
+
129
+ class BooleanSeries(Series, PyLegendBoolean, PyLegendExpressionBooleanReturn): # type: ignore
130
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
131
+ super().__init__(base_frame, column) # pragma: no cover (Boolean column not supported in PURE)
132
+ PyLegendBoolean.__init__(self, self) # pragma: no cover (Boolean column not supported in PURE)
133
+
134
+
135
+ class StringSeries(Series, PyLegendString, PyLegendExpressionStringReturn): # type: ignore
136
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
137
+ super().__init__(base_frame, column)
138
+ PyLegendString.__init__(self, self)
139
+
140
+
141
+ class NumberSeries(Series, PyLegendNumber, PyLegendExpressionNumberReturn): # type: ignore
142
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
143
+ super().__init__(base_frame, column)
144
+ PyLegendNumber.__init__(self, self)
145
+
146
+
147
+ class IntegerSeries(NumberSeries, PyLegendInteger, PyLegendExpressionIntegerReturn): # type: ignore
148
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
149
+ super().__init__(base_frame, column)
150
+ PyLegendInteger.__init__(self, self)
151
+
152
+
153
+ class FloatSeries(NumberSeries, PyLegendFloat, PyLegendExpressionFloatReturn): # type: ignore
154
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
155
+ super().__init__(base_frame, column)
156
+ PyLegendFloat.__init__(self, self)
157
+
158
+
159
+ class DateSeries(Series, PyLegendDate, PyLegendExpressionDateReturn): # type: ignore
160
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
161
+ super().__init__(base_frame, column)
162
+ PyLegendDate.__init__(self, self)
163
+
164
+
165
+ class DateTimeSeries(DateSeries, PyLegendDateTime, PyLegendExpressionDateTimeReturn): # type: ignore
166
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
167
+ super().__init__(base_frame, column)
168
+ PyLegendDateTime.__init__(self, self)
169
+
170
+
171
+ class StrictDateSeries(DateSeries, PyLegendStrictDate, PyLegendExpressionStrictDateReturn): # type: ignore
172
+ def __init__(self, base_frame: "PandasApiTdsFrame", column: str):
173
+ super().__init__(base_frame, column)
174
+ PyLegendStrictDate.__init__(self, self)
@@ -0,0 +1,74 @@
1
+ # Copyright 2025 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from pylegend._typing import (
16
+ PyLegendSequence,
17
+ )
18
+ from pylegend.core.language import (
19
+ PyLegendBoolean,
20
+ PyLegendString,
21
+ PyLegendInteger,
22
+ PyLegendFloat,
23
+ PyLegendNumber,
24
+ PyLegendStrictDate,
25
+ PyLegendDateTime,
26
+ PyLegendDate,
27
+ )
28
+ from pylegend.core.language.pandas_api.pandas_api_custom_expressions import (
29
+ PandasApiBoolean,
30
+ PandasApiString,
31
+ PandasApiInteger,
32
+ PandasApiFloat,
33
+ PandasApiNumber,
34
+ PandasApiStrictDate,
35
+ PandasApiDateTime,
36
+ PandasApiDate,
37
+ PandasApiPrimitive,
38
+ )
39
+ from pylegend.core.language.shared.tds_row import AbstractTdsRow
40
+ from pylegend.core.tds.tds_frame import PyLegendTdsFrame
41
+
42
+ __all__: PyLegendSequence[str] = [
43
+ "PandasApiTdsRow",
44
+ ]
45
+
46
+
47
+ class PandasApiTdsRow(AbstractTdsRow):
48
+ def __init__(self, frame_name: str, frame: PyLegendTdsFrame) -> None:
49
+ super().__init__(frame_name, frame)
50
+
51
+ @staticmethod
52
+ def from_tds_frame(frame_name: str, frame: PyLegendTdsFrame) -> "PandasApiTdsRow":
53
+ return PandasApiTdsRow(frame_name=frame_name, frame=frame)
54
+
55
+ def __getitem__(self, item: str) -> PandasApiPrimitive:
56
+ res = super().__getitem__(item)
57
+ if isinstance(res, PyLegendBoolean):
58
+ return PandasApiBoolean(res)
59
+ if isinstance(res, PyLegendString):
60
+ return PandasApiString(res)
61
+ if isinstance(res, PyLegendInteger):
62
+ return PandasApiInteger(res)
63
+ if isinstance(res, PyLegendFloat):
64
+ return PandasApiFloat(res)
65
+ if isinstance(res, PyLegendNumber):
66
+ return PandasApiNumber(res)
67
+ if isinstance(res, PyLegendStrictDate):
68
+ return PandasApiStrictDate(res)
69
+ if isinstance(res, PyLegendDateTime):
70
+ return PandasApiDateTime(res)
71
+ if isinstance(res, PyLegendDate):
72
+ return PandasApiDate(res)
73
+
74
+ raise RuntimeError(f"Unhandled primitive type {type(res)} in Pandas Api") # pragma: no cover
@@ -18,6 +18,7 @@ from pylegend._typing import (
18
18
  )
19
19
  from pylegend.core.language.shared.expression import (
20
20
  PyLegendExpressionIntegerReturn,
21
+ PyLegendExpressionStringReturn,
21
22
  )
22
23
  from pylegend.core.language.shared.operations.binary_expression import PyLegendBinaryExpression
23
24
  from pylegend.core.language.shared.operations.unary_expression import PyLegendUnaryExpression
@@ -28,6 +29,8 @@ from pylegend.core.sql.metamodel import (
28
29
  ArithmeticType,
29
30
  ArithmeticExpression,
30
31
  NegativeExpression,
32
+ FunctionCall,
33
+ QualifiedName
31
34
  )
32
35
  from pylegend.core.sql.metamodel_extension import (
33
36
  AbsoluteExpression,
@@ -43,6 +46,7 @@ __all__: PyLegendSequence[str] = [
43
46
  "PyLegendIntegerSubtractExpression",
44
47
  "PyLegendIntegerMultiplyExpression",
45
48
  "PyLegendIntegerModuloExpression",
49
+ "PyLegendIntegerCharExpression",
46
50
  ]
47
51
 
48
52
 
@@ -212,3 +216,34 @@ class PyLegendIntegerNegativeExpression(PyLegendUnaryExpression, PyLegendExpress
212
216
  non_nullable=True,
213
217
  operand_needs_to_be_non_nullable=True,
214
218
  )
219
+
220
+
221
+ class PyLegendIntegerCharExpression(PyLegendUnaryExpression, PyLegendExpressionStringReturn):
222
+
223
+ @staticmethod
224
+ def __to_sql_func(
225
+ expression: Expression,
226
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
227
+ config: FrameToSqlConfig
228
+ ) -> Expression:
229
+ return FunctionCall(
230
+ name=QualifiedName(parts=["CHR"]),
231
+ distinct=False,
232
+ arguments=[expression],
233
+ filter_=None, window=None
234
+ )
235
+
236
+ @staticmethod
237
+ def __to_pure_func(op_expr: str, config: FrameToPureConfig) -> str:
238
+ return generate_pure_functional_call("char", [op_expr])
239
+
240
+ def __init__(self, operand: PyLegendExpressionIntegerReturn) -> None:
241
+ PyLegendExpressionStringReturn.__init__(self)
242
+ PyLegendUnaryExpression.__init__(
243
+ self,
244
+ operand,
245
+ PyLegendIntegerCharExpression.__to_sql_func,
246
+ PyLegendIntegerCharExpression.__to_pure_func,
247
+ non_nullable=True,
248
+ operand_needs_to_be_non_nullable=True,
249
+ )
@@ -0,0 +1,104 @@
1
+ # Copyright 2025 Goldman Sachs
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from abc import ABCMeta
16
+ from pylegend._typing import (
17
+ PyLegendSequence,
18
+ PyLegendDict,
19
+ PyLegendCallable,
20
+ PyLegendList,
21
+ PyLegendOptional
22
+ )
23
+ from pylegend.core.language.shared.expression import (
24
+ PyLegendExpression,
25
+ )
26
+ from pylegend.core.language.shared.helpers import expr_has_matching_start_and_end_parentheses
27
+ from pylegend.core.sql.metamodel import (
28
+ Expression,
29
+ QuerySpecification,
30
+ )
31
+ from pylegend.core.tds.tds_frame import FrameToSqlConfig
32
+ from pylegend.core.tds.tds_frame import FrameToPureConfig
33
+
34
+ __all__: PyLegendSequence[str] = [
35
+ "PyLegendNaryExpression"
36
+ ]
37
+
38
+
39
+ class PyLegendNaryExpression(PyLegendExpression, metaclass=ABCMeta):
40
+ __operands: PyLegendList[PyLegendExpression]
41
+ __to_sql_func: PyLegendCallable[
42
+ [PyLegendList[Expression], PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
43
+ Expression
44
+ ]
45
+ __to_pure_func: PyLegendCallable[
46
+ [PyLegendList[str], FrameToPureConfig],
47
+ str
48
+ ]
49
+ __non_nullable: bool
50
+ __operands_non_nullable_flags: PyLegendList[bool]
51
+
52
+ def __init__(
53
+ self,
54
+ operands: PyLegendList[PyLegendExpression],
55
+ to_sql_func: PyLegendCallable[
56
+ [PyLegendList[Expression], PyLegendDict[str, QuerySpecification], FrameToSqlConfig],
57
+ Expression
58
+ ],
59
+ to_pure_func: PyLegendCallable[
60
+ [PyLegendList[str], FrameToPureConfig],
61
+ str
62
+ ],
63
+ non_nullable: bool = False,
64
+ operands_non_nullable_flags: PyLegendOptional[PyLegendList[bool]] = None
65
+ ) -> None:
66
+ self.__operands = operands
67
+ self.__to_sql_func = to_sql_func
68
+ self.__to_pure_func = to_pure_func
69
+ self.__non_nullable = non_nullable
70
+ self.__operands_non_nullable_flags = (
71
+ operands_non_nullable_flags
72
+ if operands_non_nullable_flags is not None
73
+ else [False] * len(operands)
74
+ )
75
+
76
+ def to_sql_expression(
77
+ self,
78
+ frame_name_to_base_query_map: PyLegendDict[str, QuerySpecification],
79
+ config: FrameToSqlConfig
80
+ ) -> Expression:
81
+ sql_operands = [
82
+ operand.to_sql_expression(frame_name_to_base_query_map, config)
83
+ for operand in self.__operands
84
+ ]
85
+ return self.__to_sql_func(sql_operands, frame_name_to_base_query_map, config)
86
+
87
+ def to_pure_expression(self, config: FrameToPureConfig) -> str:
88
+ pure_operands: PyLegendList[str] = []
89
+
90
+ for operand, must_be_non_nullable in zip(self.__operands, self.__operands_non_nullable_flags):
91
+ expr = operand.to_pure_expression(config)
92
+
93
+ if must_be_non_nullable:
94
+ expr = (
95
+ expr if operand.is_non_nullable() else
96
+ f"toOne({expr[1:-1] if expr_has_matching_start_and_end_parentheses(expr) else expr})"
97
+ )
98
+
99
+ pure_operands.append(expr)
100
+
101
+ return self.__to_pure_func(pure_operands, config)
102
+
103
+ def is_non_nullable(self) -> bool:
104
+ return self.__non_nullable