pytrilogy 0.3.138__cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
Files changed (182) hide show
  1. LICENSE.md +19 -0
  2. _preql_import_resolver/__init__.py +5 -0
  3. _preql_import_resolver/_preql_import_resolver.cpython-311-x86_64-linux-gnu.so +0 -0
  4. pytrilogy-0.3.138.dist-info/METADATA +525 -0
  5. pytrilogy-0.3.138.dist-info/RECORD +182 -0
  6. pytrilogy-0.3.138.dist-info/WHEEL +5 -0
  7. pytrilogy-0.3.138.dist-info/entry_points.txt +2 -0
  8. pytrilogy-0.3.138.dist-info/licenses/LICENSE.md +19 -0
  9. trilogy/__init__.py +9 -0
  10. trilogy/ai/README.md +10 -0
  11. trilogy/ai/__init__.py +19 -0
  12. trilogy/ai/constants.py +92 -0
  13. trilogy/ai/conversation.py +107 -0
  14. trilogy/ai/enums.py +7 -0
  15. trilogy/ai/execute.py +50 -0
  16. trilogy/ai/models.py +34 -0
  17. trilogy/ai/prompts.py +87 -0
  18. trilogy/ai/providers/__init__.py +0 -0
  19. trilogy/ai/providers/anthropic.py +106 -0
  20. trilogy/ai/providers/base.py +24 -0
  21. trilogy/ai/providers/google.py +146 -0
  22. trilogy/ai/providers/openai.py +89 -0
  23. trilogy/ai/providers/utils.py +68 -0
  24. trilogy/authoring/README.md +3 -0
  25. trilogy/authoring/__init__.py +143 -0
  26. trilogy/constants.py +113 -0
  27. trilogy/core/README.md +52 -0
  28. trilogy/core/__init__.py +0 -0
  29. trilogy/core/constants.py +6 -0
  30. trilogy/core/enums.py +443 -0
  31. trilogy/core/env_processor.py +120 -0
  32. trilogy/core/environment_helpers.py +320 -0
  33. trilogy/core/ergonomics.py +193 -0
  34. trilogy/core/exceptions.py +123 -0
  35. trilogy/core/functions.py +1227 -0
  36. trilogy/core/graph_models.py +139 -0
  37. trilogy/core/internal.py +85 -0
  38. trilogy/core/models/__init__.py +0 -0
  39. trilogy/core/models/author.py +2672 -0
  40. trilogy/core/models/build.py +2521 -0
  41. trilogy/core/models/build_environment.py +180 -0
  42. trilogy/core/models/core.py +494 -0
  43. trilogy/core/models/datasource.py +322 -0
  44. trilogy/core/models/environment.py +748 -0
  45. trilogy/core/models/execute.py +1177 -0
  46. trilogy/core/optimization.py +251 -0
  47. trilogy/core/optimizations/__init__.py +12 -0
  48. trilogy/core/optimizations/base_optimization.py +17 -0
  49. trilogy/core/optimizations/hide_unused_concept.py +47 -0
  50. trilogy/core/optimizations/inline_datasource.py +102 -0
  51. trilogy/core/optimizations/predicate_pushdown.py +245 -0
  52. trilogy/core/processing/README.md +94 -0
  53. trilogy/core/processing/READMEv2.md +121 -0
  54. trilogy/core/processing/VIRTUAL_UNNEST.md +30 -0
  55. trilogy/core/processing/__init__.py +0 -0
  56. trilogy/core/processing/concept_strategies_v3.py +508 -0
  57. trilogy/core/processing/constants.py +15 -0
  58. trilogy/core/processing/discovery_node_factory.py +451 -0
  59. trilogy/core/processing/discovery_utility.py +517 -0
  60. trilogy/core/processing/discovery_validation.py +167 -0
  61. trilogy/core/processing/graph_utils.py +43 -0
  62. trilogy/core/processing/node_generators/README.md +9 -0
  63. trilogy/core/processing/node_generators/__init__.py +31 -0
  64. trilogy/core/processing/node_generators/basic_node.py +160 -0
  65. trilogy/core/processing/node_generators/common.py +268 -0
  66. trilogy/core/processing/node_generators/constant_node.py +38 -0
  67. trilogy/core/processing/node_generators/filter_node.py +315 -0
  68. trilogy/core/processing/node_generators/group_node.py +213 -0
  69. trilogy/core/processing/node_generators/group_to_node.py +117 -0
  70. trilogy/core/processing/node_generators/multiselect_node.py +205 -0
  71. trilogy/core/processing/node_generators/node_merge_node.py +653 -0
  72. trilogy/core/processing/node_generators/recursive_node.py +88 -0
  73. trilogy/core/processing/node_generators/rowset_node.py +165 -0
  74. trilogy/core/processing/node_generators/select_helpers/__init__.py +0 -0
  75. trilogy/core/processing/node_generators/select_helpers/datasource_injection.py +261 -0
  76. trilogy/core/processing/node_generators/select_merge_node.py +748 -0
  77. trilogy/core/processing/node_generators/select_node.py +95 -0
  78. trilogy/core/processing/node_generators/synonym_node.py +98 -0
  79. trilogy/core/processing/node_generators/union_node.py +91 -0
  80. trilogy/core/processing/node_generators/unnest_node.py +182 -0
  81. trilogy/core/processing/node_generators/window_node.py +201 -0
  82. trilogy/core/processing/nodes/README.md +28 -0
  83. trilogy/core/processing/nodes/__init__.py +179 -0
  84. trilogy/core/processing/nodes/base_node.py +519 -0
  85. trilogy/core/processing/nodes/filter_node.py +75 -0
  86. trilogy/core/processing/nodes/group_node.py +194 -0
  87. trilogy/core/processing/nodes/merge_node.py +420 -0
  88. trilogy/core/processing/nodes/recursive_node.py +46 -0
  89. trilogy/core/processing/nodes/select_node_v2.py +242 -0
  90. trilogy/core/processing/nodes/union_node.py +53 -0
  91. trilogy/core/processing/nodes/unnest_node.py +62 -0
  92. trilogy/core/processing/nodes/window_node.py +56 -0
  93. trilogy/core/processing/utility.py +823 -0
  94. trilogy/core/query_processor.py +596 -0
  95. trilogy/core/statements/README.md +35 -0
  96. trilogy/core/statements/__init__.py +0 -0
  97. trilogy/core/statements/author.py +536 -0
  98. trilogy/core/statements/build.py +0 -0
  99. trilogy/core/statements/common.py +20 -0
  100. trilogy/core/statements/execute.py +155 -0
  101. trilogy/core/table_processor.py +66 -0
  102. trilogy/core/utility.py +8 -0
  103. trilogy/core/validation/README.md +46 -0
  104. trilogy/core/validation/__init__.py +0 -0
  105. trilogy/core/validation/common.py +161 -0
  106. trilogy/core/validation/concept.py +146 -0
  107. trilogy/core/validation/datasource.py +227 -0
  108. trilogy/core/validation/environment.py +73 -0
  109. trilogy/core/validation/fix.py +106 -0
  110. trilogy/dialect/__init__.py +32 -0
  111. trilogy/dialect/base.py +1359 -0
  112. trilogy/dialect/bigquery.py +256 -0
  113. trilogy/dialect/common.py +147 -0
  114. trilogy/dialect/config.py +144 -0
  115. trilogy/dialect/dataframe.py +50 -0
  116. trilogy/dialect/duckdb.py +177 -0
  117. trilogy/dialect/enums.py +147 -0
  118. trilogy/dialect/metadata.py +173 -0
  119. trilogy/dialect/mock.py +190 -0
  120. trilogy/dialect/postgres.py +91 -0
  121. trilogy/dialect/presto.py +104 -0
  122. trilogy/dialect/results.py +89 -0
  123. trilogy/dialect/snowflake.py +90 -0
  124. trilogy/dialect/sql_server.py +92 -0
  125. trilogy/engine.py +48 -0
  126. trilogy/execution/config.py +75 -0
  127. trilogy/executor.py +568 -0
  128. trilogy/hooks/__init__.py +4 -0
  129. trilogy/hooks/base_hook.py +40 -0
  130. trilogy/hooks/graph_hook.py +139 -0
  131. trilogy/hooks/query_debugger.py +166 -0
  132. trilogy/metadata/__init__.py +0 -0
  133. trilogy/parser.py +10 -0
  134. trilogy/parsing/README.md +21 -0
  135. trilogy/parsing/__init__.py +0 -0
  136. trilogy/parsing/common.py +1069 -0
  137. trilogy/parsing/config.py +5 -0
  138. trilogy/parsing/exceptions.py +8 -0
  139. trilogy/parsing/helpers.py +1 -0
  140. trilogy/parsing/parse_engine.py +2813 -0
  141. trilogy/parsing/render.py +750 -0
  142. trilogy/parsing/trilogy.lark +540 -0
  143. trilogy/py.typed +0 -0
  144. trilogy/render.py +42 -0
  145. trilogy/scripts/README.md +7 -0
  146. trilogy/scripts/__init__.py +0 -0
  147. trilogy/scripts/dependency/Cargo.lock +617 -0
  148. trilogy/scripts/dependency/Cargo.toml +39 -0
  149. trilogy/scripts/dependency/README.md +131 -0
  150. trilogy/scripts/dependency/build.sh +25 -0
  151. trilogy/scripts/dependency/src/directory_resolver.rs +162 -0
  152. trilogy/scripts/dependency/src/lib.rs +16 -0
  153. trilogy/scripts/dependency/src/main.rs +770 -0
  154. trilogy/scripts/dependency/src/parser.rs +435 -0
  155. trilogy/scripts/dependency/src/preql.pest +208 -0
  156. trilogy/scripts/dependency/src/python_bindings.rs +289 -0
  157. trilogy/scripts/dependency/src/resolver.rs +716 -0
  158. trilogy/scripts/dependency/tests/base.preql +3 -0
  159. trilogy/scripts/dependency/tests/cli_integration.rs +377 -0
  160. trilogy/scripts/dependency/tests/customer.preql +6 -0
  161. trilogy/scripts/dependency/tests/main.preql +9 -0
  162. trilogy/scripts/dependency/tests/orders.preql +7 -0
  163. trilogy/scripts/dependency/tests/test_data/base.preql +9 -0
  164. trilogy/scripts/dependency/tests/test_data/consumer.preql +1 -0
  165. trilogy/scripts/dependency.py +323 -0
  166. trilogy/scripts/display.py +460 -0
  167. trilogy/scripts/environment.py +46 -0
  168. trilogy/scripts/parallel_execution.py +483 -0
  169. trilogy/scripts/single_execution.py +131 -0
  170. trilogy/scripts/trilogy.py +772 -0
  171. trilogy/std/__init__.py +0 -0
  172. trilogy/std/color.preql +3 -0
  173. trilogy/std/date.preql +13 -0
  174. trilogy/std/display.preql +18 -0
  175. trilogy/std/geography.preql +22 -0
  176. trilogy/std/metric.preql +15 -0
  177. trilogy/std/money.preql +67 -0
  178. trilogy/std/net.preql +14 -0
  179. trilogy/std/ranking.preql +7 -0
  180. trilogy/std/report.preql +5 -0
  181. trilogy/std/semantic.preql +6 -0
  182. trilogy/utility.py +34 -0
@@ -0,0 +1,182 @@
1
+ LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
2
+ _preql_import_resolver/__init__.py,sha256=u8p6v_wq7kr8H8ZqwxeGaN1E5LW7rNe6fMjshXjpBcY,171
3
+ _preql_import_resolver/_preql_import_resolver.cpython-311-x86_64-linux-gnu.so,sha256=zm_su-1gBeY8K4YQD919-4QRQbAFnY9LENzRMsMviVY,830632
4
+ pytrilogy-0.3.138.dist-info/METADATA,sha256=JPN3_NM5YYh5d1lfHxQ6qXxbglmqVJhh-Uc1_t2gCUg,12787
5
+ pytrilogy-0.3.138.dist-info/WHEEL,sha256=4-OGKj-lgfDeqzzIOb2pgfMuLfXCZdUla629tnbzHm4,147
6
+ pytrilogy-0.3.138.dist-info/entry_points.txt,sha256=yuRY2xq7kdrpz-vxW0f1NJHKSOkxB-gXoBQVyTWftas,54
7
+ pytrilogy-0.3.138.dist-info/licenses/LICENSE.md,sha256=5ZRvtTyCCFwz1THxDTjAu3Lidds9WjPvvzgVwPSYNDo,1042
8
+ trilogy/__init__.py,sha256=h6_kOseC4aU2mx9GpH1T6sGjDr-83ujk5gIPLFmcjAc,302
9
+ trilogy/ai/README.md,sha256=IYwlSHY7pVc1Qw3Ib8koAjbMvYmhBWnZCYYOoN7Dqz0,522
10
+ trilogy/ai/__init__.py,sha256=H6gpzScruX2xgZNRDMjQ31Wy45irJbdebX1fU_gOwI8,581
11
+ trilogy/ai/constants.py,sha256=Aj-_mFqskcXqIlBjX_A9eqH0V9M8mqX3uJwUhr9puak,5064
12
+ trilogy/ai/conversation.py,sha256=Hu-Re-_6eZ6fzNxQ7T_k8tk1MB7gpaB24t-vcZk9tcU,3948
13
+ trilogy/ai/enums.py,sha256=vghPPx0W-DioQSgq4T0MGL-8ekFh6O6d52dHo7KsKtg,118
14
+ trilogy/ai/execute.py,sha256=DTARZxm_btCJq4Yd_jPRHJAcbsMLbjEsjR7KKyKBkTI,1335
15
+ trilogy/ai/models.py,sha256=Au4QnTIlv7e-p3XgTJYZqTSndPMGRIbOvCUWlekE81A,683
16
+ trilogy/ai/prompts.py,sha256=pcif-A-0h47cs1AQrVhKrcqrL7M1UuuHd9XEHtV2EPI,3782
17
+ trilogy/ai/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ trilogy/ai/providers/anthropic.py,sha256=9FaPREVFi_YAgOlQXKyeJP0aBeaz1WGtFlqv80bkPSg,4099
19
+ trilogy/ai/providers/base.py,sha256=jjGuXdkqoQy6n2y5v4qm8jRC3fIl-xUsDi6BT-AWmvg,738
20
+ trilogy/ai/providers/google.py,sha256=YTf4veSnZYPvUulk5CZ0TWIF3gJ-_HXk7YyuB2Oq2gg,5401
21
+ trilogy/ai/providers/openai.py,sha256=fYtD0eh48qRmN81-ymAEyuTE0p1rgLfNuxrHMFrA2eQ,3293
22
+ trilogy/ai/providers/utils.py,sha256=aqajhHGk_opeKElQa9iCkNjwzfmoKh_ylnFeO9dJ6kQ,2046
23
+ trilogy/authoring/README.md,sha256=5qr628ZIwknD0APOFCJMY8mtYHJMWUvcAF094AiYvlQ,147
24
+ trilogy/authoring/__init__.py,sha256=4YAsMLYpGa9V4Oj-ULUWvVCuUWQvuLNyLvoDHuDTH_o,3104
25
+ trilogy/constants.py,sha256=rU2n9bPZPIw6DXmgHvF9JUPjDzFVONZGVL6zUq7MqnE,2680
26
+ trilogy/core/README.md,sha256=nqun8GcO-pNKwZ5JHFbjA3UR6RH0lRqIlZ5Vi435h5Y,912
27
+ trilogy/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ trilogy/core/constants.py,sha256=zVSCfkSKDQ75UhpNSZBO3F62bS-o0jgyHw4S8Bht2CM,244
29
+ trilogy/core/enums.py,sha256=Id7-0N-AbOp8H00UpyT2fQDErUNlvOQqFORR7--Wlac,9832
30
+ trilogy/core/env_processor.py,sha256=H-rr2ALj31l5oh3FqeI47Qju6OOfiXBacXNJGNZ92zQ,4521
31
+ trilogy/core/environment_helpers.py,sha256=TRlqVctqIRBxzfjRBmpQsAVoiCcsEKBhG1B6PUE0l1M,12743
32
+ trilogy/core/ergonomics.py,sha256=e-7gE29vPLFdg0_A1smQ7eOrUwKl5VYdxRSTddHweRA,1631
33
+ trilogy/core/exceptions.py,sha256=ycrsMbEYruOLWdVernj30J8rGy07H4lLUn-97phKgvQ,3197
34
+ trilogy/core/functions.py,sha256=zwpM2SfRpN-3jBq5xzXOQEXCX2F-Nc9dsbxtyiWg7Fw,37169
35
+ trilogy/core/graph_models.py,sha256=l5w8Kb844o380gJyrnywDpq7eUbSwbbdix_rZgdofWU,4497
36
+ trilogy/core/internal.py,sha256=r9QagDB2GvpqlyD_I7VrsfbVfIk5mnok2znEbv72Aa4,2681
37
+ trilogy/core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ trilogy/core/models/author.py,sha256=fah2rxQCbg-dmw6CWuzzeElnkXSVJF4xdHqgPBzBtQg,86322
39
+ trilogy/core/models/build.py,sha256=SBaWcmhI-QWmtGkWTOk-KbrD2WBv7f-uMXAHsJ-5nw8,79854
40
+ trilogy/core/models/build_environment.py,sha256=AN__ygHCiK-DJQCAlQlf-WKJPJVJjpK2Y9sM6TirZss,6942
41
+ trilogy/core/models/core.py,sha256=HWcrLaZqTC-nJsrDXo7cq5f3tMUs6oYLeqYZ6E3oJMU,13515
42
+ trilogy/core/models/datasource.py,sha256=RcnWYfzCAP-g8rSv9adHGBOXxyvQJnaN1J7mSUkEEyE,10278
43
+ trilogy/core/models/environment.py,sha256=OGQjUhgZWZANjZF48QHttdgRDUwg_aiF7V2DbyA6S4s,25528
44
+ trilogy/core/models/execute.py,sha256=UWiICPDZMWMHzgGwpnvioWzGwgmTG1Ph0_JWgYcgkaA,42615
45
+ trilogy/core/optimization.py,sha256=eKieOaWXUtoNTVQbThGA5tqrI06ZR6SUFOqGe4Jw0k4,9262
46
+ trilogy/core/optimizations/__init__.py,sha256=yspWc25M5SgAuvXYoSt5J8atyPbDlOfsKjIo5yGD9s4,368
47
+ trilogy/core/optimizations/base_optimization.py,sha256=gzDOKImoFn36k7XBD3ysEYDnbnb6vdVIztUfFQZsGnM,513
48
+ trilogy/core/optimizations/hide_unused_concept.py,sha256=THp6byyh64dArSz6EuY7unik5WKgQQfWxNGToEqjqE0,1875
49
+ trilogy/core/optimizations/inline_datasource.py,sha256=2sWNRpoRInnTgo9wExVT_r9RfLAQHI57reEV5cGHUcg,4329
50
+ trilogy/core/optimizations/predicate_pushdown.py,sha256=5ubatgq1IwWQ4L2FDt4--y168YLuGP-vwqH0m8IeTIw,9786
51
+ trilogy/core/processing/README.md,sha256=cqvYntAwKGVCJS5lVieUc4vSeUrXXs-1mIYHNRKc5CI,2914
52
+ trilogy/core/processing/READMEv2.md,sha256=1rbbYKAGEG-a9TKHRy9iosNAcEDKdsQ7oYgs1I9YLkM,2954
53
+ trilogy/core/processing/VIRTUAL_UNNEST.md,sha256=ILvvg24eeCNPSxDJRIXFEEHyhJvr4bGnfVVINrkrXnc,716
54
+ trilogy/core/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
+ trilogy/core/processing/concept_strategies_v3.py,sha256=fygB_QBp7sv_Sp7zBe9MAWi71R1_DNzK2hFH7Pzk218,18998
56
+ trilogy/core/processing/constants.py,sha256=cJDTJwMxNS8msbERjFy2N-nYOUBIX584icuBMW24Nz8,404
57
+ trilogy/core/processing/discovery_node_factory.py,sha256=80pUIJZIiIGRZd-S_cNbO5da_RpUGNqOvBRwDkdrWCI,13988
58
+ trilogy/core/processing/discovery_utility.py,sha256=b3tgVyPN8_Zok70M4Rz2d7fZbmv_OBNZAItU4tgQye8,19975
59
+ trilogy/core/processing/discovery_validation.py,sha256=eZ4HfHMpqZLI8MGG2jez8arS8THs6ceuVrQFIY6gXrU,5364
60
+ trilogy/core/processing/graph_utils.py,sha256=8QUVrkE9j-9C1AyrCb1nQEh8daCe0u1HuXl-Te85lag,1205
61
+ trilogy/core/processing/node_generators/README.md,sha256=eWOTFZhVwUv3jOIBjHZiKO4YVOVz9T_Q3PpI2yaKQoY,331
62
+ trilogy/core/processing/node_generators/__init__.py,sha256=iVJ-crowPxYeut-hFjyEjfibKIDq7PfB4LEuDAUCjGY,943
63
+ trilogy/core/processing/node_generators/basic_node.py,sha256=OQPRMy75JcrzLOl_VeXtIXmE0-Vx5R8mfqkowdicBuc,6021
64
+ trilogy/core/processing/node_generators/common.py,sha256=oGUW4_RhSpfGu9PNUj0JsHB8iMeTz76FQHMcfVRHP30,9516
65
+ trilogy/core/processing/node_generators/constant_node.py,sha256=LfpDq2WrBRZ3tGsLxw77LuigKfhbteWWh9L8BGdMGwk,1146
66
+ trilogy/core/processing/node_generators/filter_node.py,sha256=EiP_tafx-X0gM-BIVRCy2rnp1_apt2cbhVfv8cg9dVg,11259
67
+ trilogy/core/processing/node_generators/group_node.py,sha256=qscOxUWggWLRETrnVz2yfqVCCi7KGjbu8SaYsFQSxqs,8560
68
+ trilogy/core/processing/node_generators/group_to_node.py,sha256=jKcNCDOY6fNblrdZwaRU0sbUSr9H0moQbAxrGgX6iGA,3832
69
+ trilogy/core/processing/node_generators/multiselect_node.py,sha256=qrgx8ofExbigipFBXKufu279vKWBLSBP91TyJW6g1qE,7135
70
+ trilogy/core/processing/node_generators/node_merge_node.py,sha256=8hFzL6HhDz-inp3DZTKd9xLKR3yUiwgwFoHCdb0M3LE,23969
71
+ trilogy/core/processing/node_generators/recursive_node.py,sha256=m851-GBAvKohWYoLbO_Ki18gRq1T1qGsKoTfrArQ8nY,2513
72
+ trilogy/core/processing/node_generators/rowset_node.py,sha256=MuVNIexXhqGONho_mewqMOwaYXNUnjjvyPvk_RDGNYE,5943
73
+ trilogy/core/processing/node_generators/select_helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ trilogy/core/processing/node_generators/select_helpers/datasource_injection.py,sha256=m2YQ4OmG0N2O61a7NEq1ZzbTa7JsCC00lxB2ymjcYRI,8224
75
+ trilogy/core/processing/node_generators/select_merge_node.py,sha256=0eiG8P_g3DVLtpDW_hc-Wqr7FCEiEK7TrgZl43KbTN4,26563
76
+ trilogy/core/processing/node_generators/select_node.py,sha256=T-KN1bsssthhE1g8WTAFD5GQft02zW_8qVkxtaBHjTs,3674
77
+ trilogy/core/processing/node_generators/synonym_node.py,sha256=AnAsa_Wj50NJ_IK0HSgab_7klYmKVrv0WI1uUe-GvEY,3766
78
+ trilogy/core/processing/node_generators/union_node.py,sha256=NxQbnRRoYMI4WjMeph41yk4E6yipj53qdGuNt-Mozxw,2818
79
+ trilogy/core/processing/node_generators/unnest_node.py,sha256=Q9E6MF6uVLqP15tlx_Bwa6mIWSNW68LJpkSYyr_TArs,6229
80
+ trilogy/core/processing/node_generators/window_node.py,sha256=wNvmumGO6AIQ7C9bDUYYZ6LJvDvPQPfFVX82pTxjV-k,6767
81
+ trilogy/core/processing/nodes/README.md,sha256=DZNyia2cNh13n0lY0QoVCmT3S0iolR6e-_ne6gwQd-g,600
82
+ trilogy/core/processing/nodes/__init__.py,sha256=zTge1EzwzEydlcMliIFO_TT7h7lS8l37lyZuQDir1h0,5487
83
+ trilogy/core/processing/nodes/base_node.py,sha256=xrtijyy38xpTt3hzVdEVaDYhk1JWAuB8yGoDJ6R82Jg,18722
84
+ trilogy/core/processing/nodes/filter_node.py,sha256=5VtRfKbCORx0dV-vQfgy3gOEkmmscL9f31ExvlODwvY,2461
85
+ trilogy/core/processing/nodes/group_node.py,sha256=Ku8El9KQvRiTiHCZDS_jX0DjErSDNv7IIQMcd1Gsk7I,7449
86
+ trilogy/core/processing/nodes/merge_node.py,sha256=4y_itKoipHKjpCIQjK9SHga-Fq-HqyeQLwAoSIFQ1hM,16567
87
+ trilogy/core/processing/nodes/recursive_node.py,sha256=k0rizxR8KE64ievfHx_GPfQmU8QAP118Laeyq5BLUOk,1526
88
+ trilogy/core/processing/nodes/select_node_v2.py,sha256=IWyKyNgFlV8A2S1FUTPdIaogg6PzaHh-HmQo6v24sbg,8862
89
+ trilogy/core/processing/nodes/union_node.py,sha256=hLAXXVWqEgMWi7dlgSHfCF59fon64av14-uPgJzoKzM,1870
90
+ trilogy/core/processing/nodes/unnest_node.py,sha256=oLKMMNMx6PLDPlt2V5neFMFrFWxET8r6XZElAhSNkO0,2181
91
+ trilogy/core/processing/nodes/window_node.py,sha256=JXJ0iVRlSEM2IBr1TANym2RaUf_p5E_l2sNykRzXWDo,1710
92
+ trilogy/core/processing/utility.py,sha256=MS5gOMH6C7L7XjYjvYVAnUST68_ff_voyWf1UWmlT2I,27359
93
+ trilogy/core/query_processor.py,sha256=nXRlb8MKRlYUJYLarsKlMbQnasymSk9o3guLTAYfdtQ,21334
94
+ trilogy/core/statements/README.md,sha256=c9KBotCNqZZGVoDPYTsonBsyBKjfHpd1D4CU3yJHrC4,450
95
+ trilogy/core/statements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
+ trilogy/core/statements/author.py,sha256=0VPmWmEUGNUhr6W_3ZD6fETyWzwKh1QacAo0Q5Bchsc,17701
97
+ trilogy/core/statements/build.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
+ trilogy/core/statements/common.py,sha256=VnVLULQg1TJLNUFzJaROT1tsf2ewk3IpuhvZaP36R6A,535
99
+ trilogy/core/statements/execute.py,sha256=UNtdzrUOuOhTOPjqukCQ8YyUOs4ZjsNj9GfaKeOEKDk,3358
100
+ trilogy/core/table_processor.py,sha256=UmYvID6L4k1wlhjjio1RS6An92x6hjk0s3ZLJFrhKhM,2180
101
+ trilogy/core/utility.py,sha256=3VC13uSQWcZNghgt7Ot0ZTeEmNqs__cx122abVq9qhM,410
102
+ trilogy/core/validation/README.md,sha256=AxU8MawVvSvBISx00LSR-aFnuGCWWsPu7JH3GT_KTDI,1617
103
+ trilogy/core/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
104
+ trilogy/core/validation/common.py,sha256=Sd-towAX1uSDe3dK51FcVtIwVrMhayEwdHqhzeJHro0,4776
105
+ trilogy/core/validation/concept.py,sha256=PM2BxBxLvuBScSWZMPsDZVcOblDil5pNT0pHLcLhdPA,5242
106
+ trilogy/core/validation/datasource.py,sha256=xFSiQ7EQVjUszJqqjOUp1Hj32Au-uEYAN6i-b4Cb8Bc,7829
107
+ trilogy/core/validation/environment.py,sha256=ymvhQyt7jLK641JAAIQkqjQaAmr9C5022ILzYvDgPP0,2835
108
+ trilogy/core/validation/fix.py,sha256=Z818UFNLxndMTLiyhB3doLxIfnOZ-16QGvVFWuD7UsA,3750
109
+ trilogy/dialect/__init__.py,sha256=5FIhcEgFEwgTmrQwggYc6ZR8hzJsbYeo8YebaViLWFQ,709
110
+ trilogy/dialect/base.py,sha256=Adxw_lpizIMA1UPI3ccjzMIE7t9qEgxb07vJtE8ilPQ,58263
111
+ trilogy/dialect/bigquery.py,sha256=R8uMZ0PoUV5QAmfw-xAZAKfZu1O34ZoltmmTRCmz9uA,9230
112
+ trilogy/dialect/common.py,sha256=I5Ku_TR5MwJTB3ZhcQenrtvXhH2RvTQ8wQe9w5lfkfA,5708
113
+ trilogy/dialect/config.py,sha256=Dxal93iNk2eNW0BmRyoIKSj1Vy-OYnA7vPD8ob5HDpM,4384
114
+ trilogy/dialect/dataframe.py,sha256=nDTHMSd7GiGjEhjAobrZND0w4zjr-vgOalM2Cdxjets,1596
115
+ trilogy/dialect/duckdb.py,sha256=uvnq2qmBHQ0fTS5c_5nuWoUyXChsP97QpG0vBc1BAPs,6581
116
+ trilogy/dialect/enums.py,sha256=70kOrxo-eNQ322z_bin7X8onWQrbghLJer8uGms9RAM,5194
117
+ trilogy/dialect/metadata.py,sha256=u7dlT23meStiGuxA_mFy5xeGH4YtKqFf8ooPjaIx6uk,5726
118
+ trilogy/dialect/mock.py,sha256=FGMmnRkRsLDCLhz_IcQcSJLDp4I8h5Q04nvpbzSURFQ,7160
119
+ trilogy/dialect/postgres.py,sha256=vF50evGW5dYftKjUL8VlypUUvv0NDIFTUD_LhngPwWc,3463
120
+ trilogy/dialect/presto.py,sha256=Vuq7kpJXW-_35wI4JT7zTGF9hr8aevxTBmgafkMR5TM,3976
121
+ trilogy/dialect/results.py,sha256=ip2bP0s6DeHkqkygfOkQj4T8m5ygWrgSJw30lOe5i2c,2315
122
+ trilogy/dialect/snowflake.py,sha256=7XyyYIK0LtgE7GWW0xGGdnit03hIxScf7mWId_jMr6o,3494
123
+ trilogy/dialect/sql_server.py,sha256=6_ogiGHQlTwg5HJiJtz3UQShVFhlr15SM296vt5XCII,3175
124
+ trilogy/engine.py,sha256=yWBfgi1xMYzhyFDpp4TmuZyAIMKacIOPLX4gJXM-t0I,983
125
+ trilogy/execution/config.py,sha256=LWCaD2HAwX2CwaGbdeisySu5weOWVn46Ki7OFrGI0xk,2402
126
+ trilogy/executor.py,sha256=5aRBqF_DBLmdjok5i_jssJFYuUs6e6GBDcpt550_MDg,19929
127
+ trilogy/hooks/__init__.py,sha256=T3SF3phuUDPLXKGRVE_Lf9mzuwoXWyaLolncR_1kY30,144
128
+ trilogy/hooks/base_hook.py,sha256=I_l-NBMNC7hKTDx1JgHZPVOOCvLQ36m2oIGaR5EUMXY,1180
129
+ trilogy/hooks/graph_hook.py,sha256=5BfR7Dt0bgEsCLgwjowgCsVkboGYfVJGOz8g9mqpnos,4756
130
+ trilogy/hooks/query_debugger.py,sha256=1npRjww94sPV5RRBBlLqMJRaFkH9vhEY6o828MeoEcw,5583
131
+ trilogy/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
+ trilogy/parser.py,sha256=o4cfk3j3yhUFoiDKq9ZX_GjBF3dKhDjXEwb63rcBkBM,293
133
+ trilogy/parsing/README.md,sha256=wSsiL1TC9dPh5ce5TtOshMsKkxHgZamM4Fav8RksiY0,433
134
+ trilogy/parsing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
135
+ trilogy/parsing/common.py,sha256=GijDRpysULL6vQWpFcjgxVASuTWXUVUi5fILHvjzkbg,35534
136
+ trilogy/parsing/config.py,sha256=Z-DaefdKhPDmSXLgg5V4pebhSB0h590vI0_VtHnlukI,111
137
+ trilogy/parsing/exceptions.py,sha256=Xwwsv2C9kSNv2q-HrrKC1f60JNHShXcCMzstTSEbiCw,154
138
+ trilogy/parsing/helpers.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
139
+ trilogy/parsing/parse_engine.py,sha256=66sl8TkU6EDn3bQysE4BMqatL-BE6fR9PnTJciJN5e0,99011
140
+ trilogy/parsing/render.py,sha256=fTdsRmfna1mxNxdSTicqTpW0EVoGE0P7fJfurMPUPb0,25188
141
+ trilogy/parsing/trilogy.lark,sha256=WrCQ7nD9z4zryIlOjE2u8Pwr-JkU9VElBgea1RrzwR4,19027
142
+ trilogy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
+ trilogy/render.py,sha256=qQWwduymauOlB517UtM-VGbVe8Cswa4UJub5aGbSO6c,1512
144
+ trilogy/scripts/README.md,sha256=qjyiw9c_uAQDC0PulOk2k8K7rLrUkmj0A0-NRIQuKgg,161
145
+ trilogy/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
+ trilogy/scripts/dependency.py,sha256=cjkVlsyuzvZ270ESTFeZBVFxjxd_Jw8By-Wwp0tWGqg,10779
147
+ trilogy/scripts/dependency/Cargo.lock,sha256=J8w4kn3iY3TG3zuZLhr1V0r--HwGT2X3YHHfKo2xWC8,15910
148
+ trilogy/scripts/dependency/Cargo.toml,sha256=0-eZ5TXtV3_uKaX3MiXGCrI1x2aJS92YHisPC7GrhLM,802
149
+ trilogy/scripts/dependency/README.md,sha256=W-xYThLW2ki1eTjlsHZfsVCTqHQueUEjpRhpMkf42QI,3599
150
+ trilogy/scripts/dependency/build.sh,sha256=csziht7F2vXVhw8Cqxzksz9Uk0ASdw-ExMogu3XNDoE,537
151
+ trilogy/scripts/dependency/src/directory_resolver.rs,sha256=Dxpbp5RFCWFirmHflEO3xPdb9tHlbtpmE9E7tJDgiyM,5093
152
+ trilogy/scripts/dependency/src/lib.rs,sha256=Bhcux66n-2pa0bwFU9aw4k7XLwBwvvVPz7SB_VGC9B8,482
153
+ trilogy/scripts/dependency/src/main.rs,sha256=LvyFiGuggJVYe-z8BtnBO3RolAoLIdKmQzlyCl1x1Lg,25316
154
+ trilogy/scripts/dependency/src/parser.rs,sha256=bGkt7k7zsr8cIhZVHpsEhd2Zgl2J-ChhVl30-zj3pXA,13483
155
+ trilogy/scripts/dependency/src/preql.pest,sha256=KQ-iduRLYDqM1UOxHuRx4hnzkErl58au8ww61bbxyIo,6687
156
+ trilogy/scripts/dependency/src/python_bindings.rs,sha256=RqkCOCsn9-5XuHyMNAH9x2uaqc_7SqfjTShrLTcv5as,10901
157
+ trilogy/scripts/dependency/src/resolver.rs,sha256=E3dLF__vLowtokHKEjSb3THHCis6tBLxWk3PVAy6B7U,24540
158
+ trilogy/scripts/dependency/tests/base.preql,sha256=Elh8JoqfyUv7zexb37FdDnlSxkocu8_MUaR16a0Kg-M,95
159
+ trilogy/scripts/dependency/tests/cli_integration.rs,sha256=CeQ6Cq3UtR18S2V6mKQ00q_FyN1EHj6YAlgQrnJ88-U,10589
160
+ trilogy/scripts/dependency/tests/customer.preql,sha256=NG5Z-rWGnQC7pAJjn-DAeGuGtrQ486worAozaIf8-Kw,149
161
+ trilogy/scripts/dependency/tests/main.preql,sha256=vDEqFCpYYx5lEnukSW3IaVlzbMnaUC3Cnrg5VttiHpE,136
162
+ trilogy/scripts/dependency/tests/orders.preql,sha256=pKkL1IhW5TfeRT64eruJ1Fe5_D9KKQlVwMO0R0STA6k,177
163
+ trilogy/scripts/dependency/tests/test_data/base.preql,sha256=4kjzTS598ZGMpDUDBqVTPU75NNPFHAWByRLay-F2btk,134
164
+ trilogy/scripts/dependency/tests/test_data/consumer.preql,sha256=CCBRBUSQxD4RBIVsiI4D1hItazXXMqHApzSW2YQOnag,13
165
+ trilogy/scripts/display.py,sha256=jvZW_2o4htv7vwwxMnwghqpSbWGpmUK4KZ5k9jUtfrk,15000
166
+ trilogy/scripts/environment.py,sha256=T66Z1h5XqTELkjs_a7Ql7M0xxHnfMGCcif86JogS5Io,1256
167
+ trilogy/scripts/parallel_execution.py,sha256=iuADJ7ovGFRG8-fmUp2ZhWqSmRijrflNBV7DTJK9sZ8,15596
168
+ trilogy/scripts/single_execution.py,sha256=Zjvkhxg1bSy1z9tTjBKSrlOnU7uGK7rUaA4XXIsiENU,4164
169
+ trilogy/scripts/trilogy.py,sha256=mUrpd9ZR5FPJWKNF8Yl-x4TBZ_LItBNzXam2Vhf4plA,23649
170
+ trilogy/std/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
171
+ trilogy/std/color.preql,sha256=sS9AXLDkECuDbNGnBMi2KnUuJukyVZVThKI9mP-ZOZI,50
172
+ trilogy/std/date.preql,sha256=HWZm4t4HWyxr5geWRsY05RnHBVDMci8z8YA2cu0-OOw,188
173
+ trilogy/std/display.preql,sha256=Jq35mrziBrj3h__RMjvBphrhg93wqXrJ2N-w6niL2LA,426
174
+ trilogy/std/geography.preql,sha256=1A9Sq5PPMBnEPPf7f-rPVYxJfsnWpQ8oV_k4Fm3H2dU,675
175
+ trilogy/std/metric.preql,sha256=DRECGhkMyqfit5Fl4Ut9zbWrJuSMI1iO9HikuyoBpE0,421
176
+ trilogy/std/money.preql,sha256=XWwvAV3WxBsHX9zfptoYRnBigcfYwrYtBHXTME0xJuQ,2082
177
+ trilogy/std/net.preql,sha256=WZCuvH87_rZntZiuGJMmBDMVKkdhTtxeHOkrXNwJ1EE,416
178
+ trilogy/std/ranking.preql,sha256=zDdmHcTerlCjaHDdVyjGTgcc2hAhnlDM_q5tiw0MPGE,108
179
+ trilogy/std/report.preql,sha256=LbV-XlHdfw0jgnQ8pV7acG95xrd1-p65fVpiIc-S7W4,202
180
+ trilogy/std/semantic.preql,sha256=k9_k672nUb5MKjSD1DW5jjn_odoYHl0yNeRPOjFabsE,95
181
+ trilogy/utility.py,sha256=euQccZLKoYBz0LNg5tzLlvv2YHvXh9HArnYp1V3uXsM,763
182
+ pytrilogy-0.3.138.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.10.2)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-cp311-manylinux_2_17_x86_64
5
+ Tag: cp311-cp311-manylinux2014_x86_64
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ trilogy=trilogy.scripts.trilogy:cli
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2023
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
trilogy/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ from trilogy.constants import CONFIG
2
+ from trilogy.core.models.environment import Environment
3
+ from trilogy.dialect.enums import Dialects
4
+ from trilogy.executor import Executor
5
+ from trilogy.parser import parse
6
+
7
+ __version__ = "0.3.138"
8
+
9
+ __all__ = ["parse", "Executor", "Dialects", "Environment", "CONFIG"]
trilogy/ai/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # AI Interaction Design
2
+
3
+ ## Overview
4
+
5
+ Core primitive is a conversation. Conversations are made up of messages. Messages have roles (user, assistant, system) and content.
6
+
7
+ A provider is used to get an additional response from the AI model. Providers can be swapped out to use different AI services (e.g., OpenAI, Anthropic, etc.).
8
+
9
+ To get out a structured output, like a query, we use a dedicated conversation method to append a message with a parser. This method will handle the validation
10
+ loop and responses to the AI.
trilogy/ai/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ from trilogy.ai.conversation import Conversation
2
+ from trilogy.ai.enums import Provider
3
+ from trilogy.ai.execute import text_to_query
4
+ from trilogy.ai.models import LLMMessage
5
+ from trilogy.ai.prompts import create_query_prompt
6
+ from trilogy.ai.providers.anthropic import AnthropicProvider
7
+ from trilogy.ai.providers.google import GoogleProvider
8
+ from trilogy.ai.providers.openai import OpenAIProvider
9
+
10
+ __all__ = [
11
+ "Conversation",
12
+ "LLMMessage",
13
+ "OpenAIProvider",
14
+ "GoogleProvider",
15
+ "AnthropicProvider",
16
+ "create_query_prompt",
17
+ "text_to_query",
18
+ "Provider",
19
+ ]
@@ -0,0 +1,92 @@
1
+ from trilogy.core.enums import FunctionClass, FunctionType
2
+ from trilogy.core.functions import FUNCTION_REGISTRY
3
+
4
+ RULE_PROMPT = """Trilogy statements define a semantic model or query. If a user is asking for data, they want a SELECT.
5
+ Semantic model statements:
6
+ - import <> imports a model to reuse. The output of imports will be visible in fields available to use.
7
+ - key|property|auto|metric defines fields locally. The output will also be visible in fields available to use, so you generally don't need to edit these unless requested.
8
+ - datasource statements define a datasource, which is a mapping of fields to a SQL database table. The left side is the SQL column name, the right side is the field name.
9
+
10
+ SELECT RULES:
11
+ - No FROM, JOIN, GROUP BY, SUB SELECTS, DISTINCT, UNION, or SELECT *.
12
+ - All fields exist in a global namespace; field paths look like `order.product.id`. Always use the full path. NEVER include a from clause.
13
+ - If a field has a grain defined, and that grain is not in the query output, aggregate it to get desired result.
14
+ - If a field has a 'alias_for' defined, it is shorthand for that calculation. Use the field name instead of the calculation in your query to be concise.
15
+ - Newly created fields at the output of the select must be aliased with as (e.g. `sum(births) as all_births`).
16
+ - Aliases cannot happen inside calculations or in the where/having/order clause. Never alias fields with existing names. 'sum(revenue) as total_revenue' is valid, but '(sum(births) as total_revenue) +1 as revenue_plus_one' is not.
17
+ - Implicit grouping: NEVER include a group by clause. Grouping is by non-aggregated fields in the SELECT clause.
18
+ - You can dynamically group inline to get groups at different grains - ex: `sum(metric) by dim1, dim2 as sum_by_dim1_dm2` for alternate grouping. If you are grouping a defined aggregate
19
+ - Count must specify a field (no `count(*)`) Counts are automatically deduplicated. Do not ever use DISTINCT.
20
+ - Since there are no underlying tables, sum/count of a constant should always specify a grain field (e.g. `sum(1) by x as count`).
21
+ - Aggregates in SELECT must be filtered via HAVING. Use WHERE for pre-aggregation filters.
22
+ - Use `field ? condition` for inline filters (e.g. `sum(x ? x > 0)`).
23
+ - Always use a reasonable `LIMIT` for final queries unless the request is for a time series or line chart.
24
+ - Window functions: `rank entity [optional over group] by field desc` (e.g. `rank name over state by sum(births) desc as top_name`) Do not use parentheses for over.
25
+ - Functions. All function names have parenthese (e.g. `sum(births)`, `date_part('year', dep_time)`). For no arguments, use empty parentheses (e.g. `current_date()`).
26
+ - For lag/lead, offset is first: lag/lead offset field order by expr asc/desc.
27
+ - For lag/lead with a window clause: lag/lead offset field by window_clause order by expr asc/desc.
28
+ - Use `::type` casting, e.g., `"2020-01-01"::date`.
29
+ - Date_parts have no quotes; use `date_part(order_date, year)` instead of `date_part(order_date, 'year')`.
30
+ - Comments use `#` only, per line.
31
+ - Two example queries: "where year between 1940 and 1950
32
+ select
33
+ name,
34
+ state,
35
+ sum(births) AS all_births,
36
+ sum(births ? state = 'VT') AS vermont_births,
37
+ rank name over state by all_births desc AS state_rank,
38
+ rank name by sum(births) by name desc AS all_rank
39
+ having
40
+ all_rank<11
41
+ and state = 'ID'
42
+ order by
43
+ all_rank asc
44
+ limit 5;", "where dep_time between '2002-01-01'::datetime and '2010-01-31'::datetime
45
+ select
46
+ carrier.name,
47
+ count(id2) AS total_flights,
48
+ total_flights / date_diff(min(dep_time.date), max(dep_time.date), DAY) AS average_daily_flights
49
+ order by
50
+ total_flights desc;"""
51
+
52
+
53
+ def render_function(function_type: FunctionType, example: str | None = None):
54
+ info = FUNCTION_REGISTRY[function_type]
55
+
56
+ if info.arg_count == -1:
57
+ # Infinite/variable number of arguments
58
+ base = f"{function_type.value}(<arg1>, <arg2>, ..., <argN>)"
59
+ elif info.arg_count == 0:
60
+ # No arguments
61
+ base = f"{function_type.value}()"
62
+ else:
63
+ # Fixed number of arguments
64
+ base = f"{function_type.value}({', '.join([f'<arg{p}>' for p in range(1, info.arg_count + 1)])})"
65
+
66
+ if example:
67
+ base += f" e.g. {example}"
68
+ return base
69
+
70
+
71
+ FUNCTION_EXAMPLES = {
72
+ FunctionType.DATE_ADD: "date_add('2020-01-01'::date, month, 1)",
73
+ FunctionType.DATE_DIFF: "date_diff('2020-01-01'::date, '2020-01-02'::date, day)",
74
+ FunctionType.DATE_PART: "date_part('2020-01-01'::date, year)",
75
+ FunctionType.DATE_SUB: "date_sub('2020-01-01'::date, day, 1)",
76
+ FunctionType.DATE_TRUNCATE: "date_trunc('2020-01-01'::date, month)",
77
+ FunctionType.CURRENT_TIMESTAMP: "now()",
78
+ }
79
+
80
+ FUNCTIONS = "\n".join(
81
+ [
82
+ render_function(v, example=FUNCTION_EXAMPLES.get(v))
83
+ for x, v in FunctionType.__members__.items()
84
+ if v in FUNCTION_REGISTRY
85
+ ]
86
+ )
87
+
88
+ AGGREGATE_FUNCTIONS = [
89
+ x
90
+ for x, info in FunctionType.__members__.items()
91
+ if x in FunctionClass.AGGREGATE_FUNCTIONS.value
92
+ ]
@@ -0,0 +1,107 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Union
3
+
4
+ from trilogy import Environment
5
+ from trilogy.ai.models import LLMMessage, LLMRequestOptions
6
+ from trilogy.ai.prompts import TRILOGY_LEAD_IN, create_query_prompt
7
+ from trilogy.ai.providers.base import LLMProvider
8
+ from trilogy.core.exceptions import (
9
+ InvalidSyntaxException,
10
+ NoDatasourceException,
11
+ UndefinedConceptException,
12
+ UnresolvableQueryException,
13
+ )
14
+ from trilogy.core.query_processor import process_query
15
+
16
+
17
+ @dataclass
18
+ class Conversation:
19
+
20
+ messages: list[LLMMessage]
21
+ provider: LLMProvider
22
+ id: str | None = None
23
+
24
+ @classmethod
25
+ def create(
26
+ cls,
27
+ provider: LLMProvider,
28
+ model_prompt: str = TRILOGY_LEAD_IN,
29
+ id: str | None = None,
30
+ ) -> "Conversation":
31
+ system_message = LLMMessage(role="system", content=model_prompt)
32
+ messages = [system_message]
33
+ return cls(id=id, messages=messages, provider=provider)
34
+
35
+ def add_message(
36
+ self,
37
+ message: Union[LLMMessage, str],
38
+ role: Literal["user", "assistant"] = "user",
39
+ ) -> None:
40
+ """
41
+ Add a message to the conversation.
42
+
43
+ Args:
44
+ message: Either an LLMMessage object or a string content
45
+ role: The role for the message if a string is provided (default: 'user')
46
+ """
47
+ if isinstance(message, str):
48
+ message = LLMMessage(role=role, content=message)
49
+ self.messages.append(message)
50
+
51
+ def get_response(self) -> LLMMessage:
52
+ options = LLMRequestOptions()
53
+ response = self.provider.generate_completion(options, history=self.messages)
54
+ response_message = LLMMessage(role="assistant", content=response.text)
55
+ self.add_message(response_message)
56
+ return response_message
57
+
58
+ def extract_response(self, content: str) -> str:
59
+ # get contents in triple backticks
60
+ content = content.replace('"""', "```")
61
+ # replace markdown trilogy code block prefix that is
62
+ # sometimes added
63
+ content = content.replace("```trilogy", "```")
64
+ if "```" in content:
65
+ parts = content.split("```")
66
+ if len(parts) >= 3:
67
+ return parts[-2].strip()
68
+ return content
69
+
70
+ def generate_query(
71
+ self, user_input: str, environment: Environment, attempts: int = 4
72
+ ) -> str:
73
+ attempts = 0
74
+ self.add_message(create_query_prompt(user_input, environment), role="user")
75
+ e = None
76
+ while attempts < 4:
77
+ attempts += 1
78
+
79
+ response_message = self.get_response()
80
+ response = self.extract_response(response_message.content)
81
+ if not response.strip():
82
+ self.add_message(
83
+ "Your response did not contain a valid Trilogy query. Please provide a valid Trilogy query enclosed in triple backticks, without a language specification.",
84
+ role="user",
85
+ )
86
+ continue
87
+ if not response.strip()[-1] == ";":
88
+ response += ";"
89
+ try:
90
+ _, raw = environment.parse(response)
91
+ process_query(statement=raw[-1], environment=environment)
92
+ return response
93
+ except (
94
+ InvalidSyntaxException,
95
+ NoDatasourceException,
96
+ UnresolvableQueryException,
97
+ UndefinedConceptException,
98
+ SyntaxError,
99
+ ) as e2:
100
+ e = e2
101
+ self.add_message(
102
+ f"Your extracted response - {response} - could not be parsed due to the error: {str(e)}. Please generate a new query with the issues fixed. Use the same response format.",
103
+ role="user",
104
+ )
105
+ raise Exception(
106
+ f"Failed to generate a valid query after {attempts} attempts. Last error: {str(e)}. Full conversation: {self.messages}"
107
+ )
trilogy/ai/enums.py ADDED
@@ -0,0 +1,7 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Provider(Enum):
5
+ OPENAI = "openai"
6
+ ANTHROPIC = "anthropic"
7
+ GOOGLE = "google"
trilogy/ai/execute.py ADDED
@@ -0,0 +1,50 @@
1
+ from trilogy import Environment
2
+ from trilogy.ai.conversation import Conversation
3
+ from trilogy.ai.enums import Provider
4
+ from trilogy.ai.providers.base import LLMProvider
5
+
6
+
7
+ def text_to_query(
8
+ environment: Environment,
9
+ user_input: str,
10
+ provider: Provider,
11
+ model: str,
12
+ secret: str | None = None,
13
+ ) -> str:
14
+ llm_provider: LLMProvider
15
+
16
+ if provider == Provider.OPENAI:
17
+ from trilogy.ai.providers.openai import OpenAIProvider
18
+
19
+ llm_provider = OpenAIProvider(
20
+ name="openai",
21
+ api_key=secret,
22
+ model=model,
23
+ )
24
+ elif provider == Provider.ANTHROPIC:
25
+ from trilogy.ai.providers.anthropic import AnthropicProvider
26
+
27
+ llm_provider = AnthropicProvider(
28
+ name="anthropic",
29
+ api_key=secret,
30
+ model=model,
31
+ )
32
+ elif provider == Provider.GOOGLE:
33
+ from trilogy.ai.providers.google import GoogleProvider
34
+
35
+ llm_provider = GoogleProvider(
36
+ name="google",
37
+ api_key=secret,
38
+ model=model,
39
+ )
40
+ else:
41
+ raise ValueError(f"Unsupported provider: {provider}")
42
+ conversation = Conversation.create(
43
+ provider=llm_provider,
44
+ )
45
+
46
+ response = conversation.generate_query(
47
+ user_input=user_input, environment=environment
48
+ )
49
+
50
+ return response
trilogy/ai/models.py ADDED
@@ -0,0 +1,34 @@
1
+ from dataclasses import dataclass
2
+ from typing import Literal, Optional
3
+
4
+
5
+ @dataclass
6
+ class UsageDict:
7
+ prompt_tokens: int
8
+ completion_tokens: int
9
+ total_tokens: int
10
+
11
+
12
+ @dataclass
13
+ class LLMResponse:
14
+ text: str
15
+ usage: UsageDict
16
+
17
+
18
+ @dataclass
19
+ class LLMRequestOptions:
20
+ max_tokens: Optional[int] = None
21
+ temperature: Optional[float] = None
22
+ top_p: Optional[float] = None
23
+
24
+
25
+ @dataclass
26
+ class LLMMessage:
27
+ role: Literal["user", "assistant", "system"]
28
+ content: str
29
+ model_info: Optional[dict] = None
30
+ hidden: bool = False # Used to hide messages in the UI
31
+
32
+ def __post_init__(self):
33
+ if self.model_info is None:
34
+ self.model_info = {}
trilogy/ai/prompts.py ADDED
@@ -0,0 +1,87 @@
1
+ from trilogy import Environment
2
+ from trilogy.ai.constants import AGGREGATE_FUNCTIONS, FUNCTIONS, RULE_PROMPT
3
+ from trilogy.authoring import (
4
+ ArrayType,
5
+ Concept,
6
+ DataType,
7
+ MapType,
8
+ NumericType,
9
+ StructType,
10
+ TraitDataType,
11
+ )
12
+ from trilogy.core.models.core import DataTyped, StructComponent
13
+
14
+ TRILOGY_LEAD_IN = f'''You are a world-class expert in Trilogy, a SQL inspired language with similar syntax and a built in semantic layer. Use the following syntax description to help answer whatever questions they have. Often, they will be asking you to generate a query for them.
15
+
16
+ Key Trilogy Syntax Rules:
17
+ {RULE_PROMPT}
18
+
19
+ Aggregate Functions:
20
+ {AGGREGATE_FUNCTIONS}
21
+
22
+ Functions:
23
+ {FUNCTIONS}
24
+
25
+ Valid types:
26
+ {[x.value for x in DataType]}
27
+
28
+ Some types may have additional metadata, which will help you understand them. For example, 'latitude', 'longitude' and 'currency' are all of type 'float', but have additional meaning.
29
+
30
+ For any response to the user, use this format -> put your actual response within triple double quotes with thinking and justification before it, in this format (replace placeholders with relevant content): Reasoning: {{reasoning}} """{{response}}"""
31
+ '''
32
+
33
+
34
+ def datatype_to_field_prompt(
35
+ datatype: (
36
+ DataType
37
+ | TraitDataType
38
+ | ArrayType
39
+ | StructType
40
+ | MapType
41
+ | NumericType
42
+ | DataTyped
43
+ | StructComponent
44
+ | int
45
+ | float
46
+ | str
47
+ ),
48
+ ) -> str:
49
+ if isinstance(datatype, TraitDataType):
50
+ return f"{datatype_to_field_prompt(datatype.type)}({','.join(datatype.traits)})"
51
+ if isinstance(datatype, ArrayType):
52
+ return f"ARRAY<{datatype_to_field_prompt(datatype.type)}>"
53
+ if isinstance(datatype, StructType):
54
+ instantiated = []
55
+ for name, field_type in datatype.field_types.items():
56
+ if isinstance(field_type, StructComponent):
57
+ instantiated.append(f"{datatype_to_field_prompt(field_type.type)}")
58
+ else:
59
+ instantiated.append(f"{name}: {datatype_to_field_prompt(field_type)}")
60
+ fields_str = ", ".join(instantiated)
61
+ return f"STRUCT<{fields_str}>"
62
+ if isinstance(datatype, MapType):
63
+ return f"MAP<{datatype_to_field_prompt(datatype.key_type)}, {datatype_to_field_prompt(datatype.value_type)}>"
64
+ if isinstance(datatype, NumericType):
65
+ return f"NUMERIC({datatype.precision}, {datatype.scale})>"
66
+ if isinstance(datatype, DataTyped):
67
+ return datatype_to_field_prompt(datatype.output_datatype)
68
+ if isinstance(datatype, StructComponent):
69
+ return f"{datatype.name}: {datatype_to_field_prompt(datatype.type)}"
70
+ if isinstance(datatype, (int, float, str)):
71
+ return f"{datatype}"
72
+ return f"{datatype.value}"
73
+
74
+
75
+ def concepts_to_fields_prompt(concepts: list[Concept]) -> str:
76
+ return ", ".join(
77
+ [
78
+ f"[name: {c.address} | type: {datatype_to_field_prompt(c.datatype)}]"
79
+ for c in concepts
80
+ ]
81
+ )
82
+
83
+
84
+ def create_query_prompt(query: str, environment: Environment) -> str:
85
+ fields = concepts_to_fields_prompt(list(environment.concepts.values()))
86
+ return f'''
87
+ Using these base and aliased calculations, derivations thereof created with valid Trilogy, and any extra context you have: {fields}, create the best valid Trilogy query to answer the following user input: "{query}" Return the query within triple double quotes with your thinking and justification before it, so of this form as a jinja template: Reasoning: {{reasoning_placeholder}} """{{trilogy}}""". Example: Because the user asked for sales by year, and revenue is the best sales related field available, we can aggregate revenue by year: """SELECT order.year, sum(revenue) as year_revenue order by order.year asc;"""'''
File without changes