datajunction 0.0.199__tar.gz → 0.0.201__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 (184) hide show
  1. {datajunction-0.0.199 → datajunction-0.0.201}/PKG-INFO +1 -1
  2. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/__about__.py +1 -1
  3. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/deployment.py +42 -1
  4. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_deploy.py +40 -0
  5. {datajunction-0.0.199 → datajunction-0.0.201}/.coveragerc +0 -0
  6. {datajunction-0.0.199 → datajunction-0.0.201}/.gitignore +0 -0
  7. {datajunction-0.0.199 → datajunction-0.0.201}/.pre-commit-config.yaml +0 -0
  8. {datajunction-0.0.199 → datajunction-0.0.201}/LICENSE.txt +0 -0
  9. {datajunction-0.0.199 → datajunction-0.0.201}/Makefile +0 -0
  10. {datajunction-0.0.199 → datajunction-0.0.201}/README.md +0 -0
  11. {datajunction-0.0.199 → datajunction-0.0.201}/claude_desktop_config.example.json +0 -0
  12. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/__init__.py +0 -0
  13. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/_base.py +0 -0
  14. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/_internal.py +0 -0
  15. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/admin.py +0 -0
  16. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/builder.py +0 -0
  17. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/cli.py +0 -0
  18. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/client.py +0 -0
  19. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/compile.py +0 -0
  20. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/exceptions.py +0 -0
  21. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/mcp/__init__.py +0 -0
  22. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/mcp/cli.py +0 -0
  23. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/mcp/config.py +0 -0
  24. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/models.py +0 -0
  25. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/nodes.py +0 -0
  26. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/rendering.py +0 -0
  27. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/init_system_nodes.py +0 -0
  28. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/date.yaml +0 -0
  29. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/deployment.yaml +0 -0
  30. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/dimension_link.yaml +0 -0
  31. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/distinct_node_authors.yaml +0 -0
  32. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/distinct_node_editors.yaml +0 -0
  33. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/dj.yaml +0 -0
  34. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/is_active.yaml +0 -0
  35. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/materialization.yaml +0 -0
  36. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_deployment_duration_seconds.yaml +0 -0
  37. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_dim_links_per_node.yaml +0 -0
  38. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_dimension_indegree.yaml +0 -0
  39. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_downstream_count.yaml +0 -0
  40. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_revisions_per_node.yaml +0 -0
  41. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/median_upstream_count.yaml +0 -0
  42. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/namespace.yaml +0 -0
  43. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/node_revision.yaml +0 -0
  44. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/node_type.yaml +0 -0
  45. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/nodes.yaml +0 -0
  46. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_branches.yaml +0 -0
  47. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_deployments.yaml +0 -0
  48. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_materializations.yaml +0 -0
  49. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_namespaces.yaml +0 -0
  50. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_nodes.yaml +0 -0
  51. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_orphan_nodes.yaml +0 -0
  52. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/number_of_unused_dimensions.yaml +0 -0
  53. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/repo.yaml +0 -0
  54. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/seed/nodes/user.yaml +0 -0
  55. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/skills/datajunction/SKILL.md +0 -0
  56. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/skills/datajunction-api/SKILL.md +0 -0
  57. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/skills/datajunction-query/SKILL.md +0 -0
  58. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/skills/datajunction-repo/SKILL.md +0 -0
  59. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/skills/datajunction-semantic-model/SKILL.md +0 -0
  60. {datajunction-0.0.199 → datajunction-0.0.201}/datajunction/tags.py +0 -0
  61. {datajunction-0.0.199 → datajunction-0.0.201}/pyproject.toml +0 -0
  62. {datajunction-0.0.199 → datajunction-0.0.201}/setup.cfg +0 -0
  63. {datajunction-0.0.199 → datajunction-0.0.201}/tests/__init__.py +0 -0
  64. {datajunction-0.0.199 → datajunction-0.0.201}/tests/conftest.py +0 -0
  65. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/dj.yaml +0 -0
  66. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/companies.yaml +0 -0
  67. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/companies_dim.yaml +0 -0
  68. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/contractor.yaml +0 -0
  69. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/contractors.yaml +0 -0
  70. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/us_state.yaml +0 -0
  71. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/deploy0/roads/us_states.yaml +0 -0
  72. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/dj.yaml +0 -0
  73. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/avg_length_of_employment.metric.yaml +0 -0
  74. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/avg_repair_price.metric.yaml +0 -0
  75. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/avg_time_to_dispatch.metric.yaml +0 -0
  76. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/contractor.dimension.yaml +0 -0
  77. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/contractors.source.yaml +0 -0
  78. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/date.source.yaml +0 -0
  79. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/date_dim.dimension.yaml +0 -0
  80. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/dispatcher.dimension.yaml +0 -0
  81. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/dispatchers.source.yaml +0 -0
  82. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/hard_hat.dimension.yaml +0 -0
  83. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/hard_hat_state.source.yaml +0 -0
  84. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/hard_hats.source.yaml +0 -0
  85. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/local_hard_hats.dimension.yaml +0 -0
  86. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/municipality.source.yaml +0 -0
  87. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/municipality_dim.dimension.yaml +0 -0
  88. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/municipality_municipality_type.source.yaml +0 -0
  89. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/municipality_type.source.yaml +0 -0
  90. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/national_level_agg.transform.yaml +0 -0
  91. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/num_repair_orders.metric.yaml +0 -0
  92. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/regional_level_agg.transform.yaml +0 -0
  93. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/regional_repair_efficiency.metric.yaml +0 -0
  94. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_order.dimension.yaml +0 -0
  95. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_order_details.source.yaml +0 -0
  96. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_order_transform.transform.yaml +0 -0
  97. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_orders.source.yaml +0 -0
  98. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_orders_cube.cube.yaml +0 -0
  99. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/repair_type.source.yaml +0 -0
  100. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/total_repair_cost.metric.yaml +0 -0
  101. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/total_repair_order_discounts.metric.yaml +0 -0
  102. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/us_region.source.yaml +0 -0
  103. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/us_state.dimension.yaml +0 -0
  104. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project1/roads/us_states.source.yaml +0 -0
  105. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project10/dj.yaml +0 -0
  106. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/avg_length_of_employment.metric.yaml +0 -0
  107. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/avg_repair_price.metric.yaml +0 -0
  108. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/avg_time_to_dispatch.metric.yaml +0 -0
  109. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/contractor.dimension.yaml +0 -0
  110. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/contractors.source.yaml +0 -0
  111. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/date.source.yaml +0 -0
  112. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/date_dim.dimension.yaml +0 -0
  113. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/dispatcher.dimension.yaml +0 -0
  114. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/dispatchers.source.yaml +0 -0
  115. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/dj.yaml +0 -0
  116. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/hard_hat.dimension.yaml +0 -0
  117. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/hard_hat_state.source.yaml +0 -0
  118. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/hard_hats.source.yaml +0 -0
  119. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/local_hard_hats.dimension.yaml +0 -0
  120. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/municipality.source.yaml +0 -0
  121. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/municipality_dim.dimension.yaml +0 -0
  122. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/municipality_municipality_type.source.yaml +0 -0
  123. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/municipality_type.source.yaml +0 -0
  124. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/national_level_agg.transform.yaml +0 -0
  125. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/num_repair_orders.metric.yaml +0 -0
  126. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/regional_level_agg.transform.yaml +0 -0
  127. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/regional_repair_efficiency.metric.yaml +0 -0
  128. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_order.dimension.yaml +0 -0
  129. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_order_details.source.yaml +0 -0
  130. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_order_transform.transform.yaml +0 -0
  131. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_orders.source.yaml +0 -0
  132. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_orders_cube.cube.yaml +0 -0
  133. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/repair_type.source.yaml +0 -0
  134. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/total_repair_cost.metric.yaml +0 -0
  135. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/total_repair_order_discounts.metric.yaml +0 -0
  136. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/us_region.source.yaml +0 -0
  137. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/us_state.dimension.yaml +0 -0
  138. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project11/us_states.source.yaml +0 -0
  139. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/dj.yaml +0 -0
  140. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/companies.source.yaml +0 -0
  141. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/companies_dim.dimension.yaml +0 -0
  142. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/contractor.dimension.yaml +0 -0
  143. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/contractors.source.yaml +0 -0
  144. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/us_state.dimension.yaml +0 -0
  145. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project12/roads/us_states.source.yaml +0 -0
  146. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project2/dj.yaml +0 -0
  147. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project2/some_node.source.yaml +0 -0
  148. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project3/dj.yaml +0 -0
  149. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project3/some_node.yaml +0 -0
  150. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project4/dj.yaml +0 -0
  151. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project4/very/very/deeply/nested/namespace/some_node.source.yaml +0 -0
  152. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project5/dj.yaml +0 -0
  153. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project5/some_node.a.b.c.source.yaml +0 -0
  154. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project6/dj.yaml +0 -0
  155. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project6/roads/contractor.dimension.yaml +0 -0
  156. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project6/roads/contractors.source.yaml +0 -0
  157. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project7/dj.yaml +0 -0
  158. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project7/roads/contractor.dimension.yaml +0 -0
  159. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project7/roads/contractors.source.yaml +0 -0
  160. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project8/dj.yaml +0 -0
  161. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/dj.yaml +0 -0
  162. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/companies.source.yaml +0 -0
  163. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/companies_dim.dimension.yaml +0 -0
  164. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/contractor.dimension.yaml +0 -0
  165. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/contractors.source.yaml +0 -0
  166. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/us_state.dimension.yaml +0 -0
  167. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples/project9/roads/us_states.source.yaml +0 -0
  168. {datajunction-0.0.199 → datajunction-0.0.201}/tests/examples.py +0 -0
  169. {datajunction-0.0.199 → datajunction-0.0.201}/tests/mcp/README.md +0 -0
  170. {datajunction-0.0.199 → datajunction-0.0.201}/tests/mcp/__init__.py +0 -0
  171. {datajunction-0.0.199 → datajunction-0.0.201}/tests/mcp/test_cli.py +0 -0
  172. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test__internal.py +0 -0
  173. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_admin.py +0 -0
  174. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_base.py +0 -0
  175. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_builder.py +0 -0
  176. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_cli.py +0 -0
  177. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_client.py +0 -0
  178. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_compile.py +0 -0
  179. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_generated_client.py +0 -0
  180. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_integration.py +0 -0
  181. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_models.py +0 -0
  182. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_plugin_mirror.py +0 -0
  183. {datajunction-0.0.199 → datajunction-0.0.201}/tests/test_skills.py +0 -0
  184. {datajunction-0.0.199 → datajunction-0.0.201}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datajunction
3
- Version: 0.0.199
3
+ Version: 0.0.201
4
4
  Summary: DataJunction client library for connecting to a DataJunction server
5
5
  Project-URL: repository, https://github.com/DataJunction/dj
6
6
  Author-email: DataJunction Authors <yian.shang@gmail.com>
@@ -2,4 +2,4 @@
2
2
  Version for Hatch
3
3
  """
4
4
 
5
- __version__ = "0.0.199"
5
+ __version__ = "0.0.201"
@@ -46,6 +46,24 @@ class ResultStatus(str, Enum):
46
46
  NOOP = "noop"
47
47
 
48
48
 
49
+ class SpecKind(str, Enum):
50
+ """
51
+ Top-level ``kind`` discriminator on a project YAML file.
52
+
53
+ A file with no ``kind`` defaults to ``NODE`` (backwards compatible: existing
54
+ files carry no discriminator). Pre-aggregations live in the same tree but
55
+ are not nodes, so they declare ``kind: preagg`` and route to the
56
+ deployment's ``preaggregations`` list.
57
+ """
58
+
59
+ NODE = "node"
60
+ PREAGG = "preagg"
61
+
62
+ @classmethod
63
+ def default(cls) -> "SpecKind":
64
+ return cls.NODE
65
+
66
+
49
67
  class DeploymentService:
50
68
  """
51
69
  High-level deployment client for exporting and importing DJ namespaces.
@@ -489,7 +507,29 @@ class DeploymentService:
489
507
  )
490
508
 
491
509
  project_metadata = self._read_project_yaml(base_dir)
492
- nodes, warnings = self._collect_nodes_from_dir(base_dir)
510
+ collected, warnings = self._collect_nodes_from_dir(base_dir)
511
+
512
+ # Every YAML file declares its ``kind`` (see SpecKind); an absent
513
+ # discriminator defaults to a node. Pre-aggregation specs live in the
514
+ # same tree but are not nodes, so they are routed to the deployment's
515
+ # ``preaggregations`` list. The key is stripped so it never reaches the
516
+ # node/pre-agg payload.
517
+ nodes: list[dict[str, Any]] = []
518
+ preaggregations: list[dict[str, Any]] = []
519
+ for item in collected:
520
+ raw_kind = item.pop("kind", SpecKind.default().value)
521
+ try:
522
+ kind = SpecKind(raw_kind)
523
+ except ValueError:
524
+ raise DJClientException(
525
+ f"Unknown kind '{raw_kind}' in "
526
+ f"'{item.get('name', '<unnamed>')}'; expected one of "
527
+ f"{[k.value for k in SpecKind]}.",
528
+ )
529
+ if kind is SpecKind.PREAGG:
530
+ preaggregations.append(item)
531
+ else:
532
+ nodes.append(item)
493
533
 
494
534
  # Deduplicate nodes by name (keep last occurrence)
495
535
  seen_names: dict[str, dict] = {}
@@ -508,6 +548,7 @@ class DeploymentService:
508
548
  or project_metadata.get("prefix", ""),
509
549
  "nodes": nodes,
510
550
  "tags": project_metadata.get("tags", []),
551
+ "preaggregations": preaggregations,
511
552
  }
512
553
 
513
554
  # Add deployment source if available from env vars
@@ -45,6 +45,46 @@ def test_pull_extracts_zip_from_server(tmp_path):
45
45
  assert (tmp_path / "foo" / "bar" / "baz.yaml").exists()
46
46
 
47
47
 
48
+ def test_reconstruct_deployment_spec_separates_preaggregations(tmp_path):
49
+ """Files with ``kind: preagg`` route to preaggregations; the rest are nodes."""
50
+ (tmp_path / "dj.yaml").write_text("namespace: ns\n")
51
+ (tmp_path / "revenue.yaml").write_text(
52
+ "name: ns.revenue\nnode_type: metric\nquery: SELECT SUM(amount) FROM ns.fct\n",
53
+ )
54
+ (tmp_path / "revenue_by_day.yaml").write_text(
55
+ "kind: preagg\n"
56
+ "name: revenue_by_day\n"
57
+ "metrics:\n - ns.revenue\n"
58
+ "dimensions:\n - ns.date.day\n"
59
+ "catalog: default\n"
60
+ "schema: agg\n"
61
+ "table: revenue_agg\n"
62
+ "measure_columns:\n ns.revenue: revenue_sum\n",
63
+ )
64
+
65
+ svc = DeploymentService(MagicMock())
66
+ spec, _ = svc._reconstruct_deployment_spec(tmp_path)
67
+
68
+ # The node file (no kind → node) stays a node.
69
+ assert [node["name"] for node in spec["nodes"]] == ["ns.revenue"]
70
+ assert len(spec["preaggregations"]) == 1
71
+ preagg = spec["preaggregations"][0]
72
+ assert preagg["name"] == "revenue_by_day"
73
+ assert preagg["measure_columns"] == {"ns.revenue": "revenue_sum"}
74
+ # The discriminator is stripped before reaching the payload.
75
+ assert "kind" not in preagg
76
+
77
+
78
+ def test_reconstruct_deployment_spec_rejects_unknown_kind(tmp_path):
79
+ """An unrecognized ``kind`` fails loudly instead of silently becoming a node."""
80
+ (tmp_path / "dj.yaml").write_text("namespace: ns\n")
81
+ (tmp_path / "mystery.yaml").write_text("kind: widget\nname: ns.mystery\n")
82
+
83
+ svc = DeploymentService(MagicMock())
84
+ with pytest.raises(DJClientException, match="Unknown kind 'widget'"):
85
+ svc._reconstruct_deployment_spec(tmp_path)
86
+
87
+
48
88
  def test_pull_uploads_existing_yaml_files(tmp_path):
49
89
  (tmp_path / "old.yaml").write_text("name: ns.old\n")
50
90
  updated_zip = _make_zip({"old.yaml": "name: ns.old\nquery: SELECT 2\n"})
File without changes
File without changes
File without changes
File without changes