Skip to content

Commit 713ace3

Browse files
committed
refactor(native): read remaining planner models and project collections natively
Plan entries, phases, identity metadata, scenarios, selectors and the audit, seed, test, display and clone command plans read a model's name, destination, key, schema entry, config, references and enum columns, and iterate the project's models, sources, seeds, functions, audits and SQL tests, through the native view helpers. A named collection lookup serves the callers that pick the collection by name.
1 parent 0610be2 commit 713ace3

25 files changed

Lines changed: 130 additions & 75 deletions

File tree

‎crates/sqlbuild-python/src/bindings/_helpers/compiled_views/model_reads.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,3 +314,12 @@ pub(crate) fn deps<'py>(model: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>
314314
}
315315
native_field(model, "deps")
316316
}
317+
318+
/// The model's enum columns by name.
319+
pub(crate) fn enum_columns<'py>(model: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
320+
let py: Python<'py> = model.py();
321+
if let Some(view) = native_model(model)? {
322+
return Ok(view.enum_columns(py)?.into_bound(py).into_any());
323+
}
324+
native_field(model, "enum_columns")
325+
}

‎crates/sqlbuild-python/src/bindings/_helpers/compiled_views/project_reads.rs‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ use crate::bindings::_helpers::compile_driver::stage_work::{COMPILED_VIEW_FALLBA
66
use crate::bindings::_helpers::compiled_views::project_view::NativeProjectView;
77
use crate::bindings::_helpers::records::fields::field as native_field;
88

9+
const MODELS_FIELD: &str = "models";
10+
const SOURCES_FIELD: &str = "sources";
11+
const SEEDS_FIELD: &str = "seeds";
12+
const FUNCTIONS_FIELD: &str = "functions";
13+
const AUDITS_FIELD: &str = "audits";
14+
915
/// The native view behind a project object; any other object is a Python-built record, counted.
1016
#[inline]
1117
fn native_project<'a>(project: &'a Bound<'_, PyAny>) -> PyResult<Option<&'a NativeProjectView>> {
@@ -22,7 +28,7 @@ pub(crate) fn models<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py, Py
2228
if let Some(view) = native_project(project)? {
2329
return Ok(view.models(py).into_bound(py).into_any());
2430
}
25-
native_field(project, "models")
31+
native_field(project, MODELS_FIELD)
2632
}
2733

2834
/// The project's compiled sources.
@@ -31,7 +37,7 @@ pub(crate) fn sources<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py, P
3137
if let Some(view) = native_project(project)? {
3238
return Ok(view.sources(py).into_bound(py));
3339
}
34-
native_field(project, "sources")
40+
native_field(project, SOURCES_FIELD)
3541
}
3642

3743
/// The project's compiled functions.
@@ -40,7 +46,7 @@ pub(crate) fn functions<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py,
4046
if let Some(view) = native_project(project)? {
4147
return Ok(view.functions(py).into_bound(py));
4248
}
43-
native_field(project, "functions")
49+
native_field(project, FUNCTIONS_FIELD)
4450
}
4551

4652
/// The project's compiled seeds.
@@ -49,7 +55,7 @@ pub(crate) fn seeds<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyA
4955
if let Some(view) = native_project(project)? {
5056
return Ok(view.seeds(py).into_bound(py));
5157
}
52-
native_field(project, "seeds")
58+
native_field(project, SEEDS_FIELD)
5359
}
5460

5561
/// The project's compiled audits.
@@ -58,5 +64,29 @@ pub(crate) fn audits<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py, Py
5864
if let Some(view) = native_project(project)? {
5965
return Ok(view.audits(py).into_bound(py));
6066
}
61-
native_field(project, "audits")
67+
native_field(project, AUDITS_FIELD)
68+
}
69+
70+
/// The project's resource collection named `field`; any other field is read by attribute.
71+
pub(crate) fn collection<'py>(
72+
project: &Bound<'py, PyAny>,
73+
field: &str,
74+
) -> PyResult<Bound<'py, PyAny>> {
75+
match field {
76+
MODELS_FIELD => models(project),
77+
SOURCES_FIELD => sources(project),
78+
SEEDS_FIELD => seeds(project),
79+
FUNCTIONS_FIELD => functions(project),
80+
AUDITS_FIELD => audits(project),
81+
_ => native_field(project, field),
82+
}
83+
}
84+
85+
/// The project's compiled SQL tests.
86+
pub(crate) fn sql_tests<'py>(project: &Bound<'py, PyAny>) -> PyResult<Bound<'py, PyAny>> {
87+
let py: Python<'py> = project.py();
88+
if let Some(view) = native_project(project)? {
89+
return Ok(view.sql_tests(py).into_bound(py));
90+
}
91+
native_field(project, "sql_tests")
6292
}

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/clone_plans.rs‎

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
44
use crate::bindings::_helpers::boundary::python_calls::keywords;
55
use crate::bindings::_helpers::compiled_views::model_reads;
6+
use crate::bindings::_helpers::compiled_views::project_reads;
67
use crate::bindings::_helpers::graph::project_graph::NativeProjectGraph;
78
use crate::bindings::_helpers::model_config::typed_config::{config_node_of, model_values};
89
use crate::bindings::_helpers::planner_entries::models::ModelPlanContext;
@@ -121,13 +122,13 @@ fn resolved_source_entries<'py>(
121122
let source_type = enum_member(py, RecordId::CompiledResourceType, "SOURCE")?;
122123
let read = PySet::empty(py)?;
123124
let mut readers: Vec<Bound<'py, PyAny>> = Vec::new();
124-
for model in native_field(project, "models")?.try_iter()? {
125+
for model in project_reads::models(project)?.try_iter()? {
125126
let model = model?;
126127
if recreated_view(&model, &selected)? {
127128
readers.push(model);
128129
}
129130
}
130-
for function in native_field(project, "functions")?.try_iter()? {
131+
for function in project_reads::functions(project)?.try_iter()? {
131132
let function = function?;
132133
if selected.contains(native_field(&function, "key")?)? {
133134
readers.push(function);
@@ -157,14 +158,11 @@ fn clone_resolution<'py>(
157158
(adapter, connection): (&Bound<'py, PyAny>, &Bound<'py, PyAny>),
158159
) -> PyResult<CloneResolution<'py>> {
159160
let py = project.py();
160-
let model_locations = object(
161-
py,
162-
build_model_locations(&native_field(project, "models")?)?,
163-
)?;
164-
let seed_locations = object(py, build_seed_locations(&native_field(project, "seeds")?)?)?;
161+
let model_locations = object(py, build_model_locations(&project_reads::models(project)?)?)?;
162+
let seed_locations = object(py, build_seed_locations(&project_reads::seeds(project)?)?)?;
165163
let function_locations = object(
166164
py,
167-
build_function_locations(&native_field(project, "functions")?)?,
165+
build_function_locations(&project_reads::functions(project)?)?,
168166
)?;
169167
let source_map = PyDict::new(py);
170168
for source in native_field(source_project, "sources")?.try_iter()? {
@@ -232,15 +230,15 @@ fn clone_model_entries<'py>(
232230
let py = project.py();
233231
let selected = native_field(plan, "selected_keys")?;
234232
let entries = PyDict::new(py);
235-
for model in native_field(project, "models")?.try_iter()? {
233+
for model in project_reads::models(project)?.try_iter()? {
236234
let model = model?;
237235
if !selected.contains(model_reads::model_key(&model)?)? || disabled_model(&model)? {
238236
continue;
239237
}
240238
let materialization_type = materialization_of(&model)?;
241239
let resolved_sql = if materialization_type.eq(VIEW_MATERIALIZATION)? {
242240
let functions = PyDict::new(py);
243-
for function in native_field(project, "functions")?.try_iter()? {
241+
for function in project_reads::functions(project)?.try_iter()? {
244242
let function = function?;
245243
functions.set_item(native_field(&function, "name")?, function)?;
246244
}
@@ -301,7 +299,7 @@ fn clone_source_entries<'py>(
301299
) -> PyResult<Bound<'py, PyAny>> {
302300
let py = project.py();
303301
let entries = PyDict::new(py);
304-
for source in native_field(project, "sources")?.try_iter()? {
302+
for source in project_reads::sources(project)?.try_iter()? {
305303
let source = source?;
306304
let entry = native_field(&source, "source_entry")?;
307305
if !selected.contains(native_field(&source, "key")?)?
@@ -359,7 +357,7 @@ fn clone_function_entries<'py>(
359357
let py = project.py();
360358
let selected = native_field(plan, "selected_keys")?;
361359
let entries = PyDict::new(py);
362-
for function in native_field(project, "functions")?.try_iter()? {
360+
for function in project_reads::functions(project)?.try_iter()? {
363361
let function = function?;
364362
if !selected.contains(native_field(&function, "key")?)? {
365363
continue;
@@ -445,7 +443,7 @@ fn seed_entries<'py>(
445443
wanted: &Bound<'py, PyAny>,
446444
) -> PyResult<Bound<'py, PyAny>> {
447445
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
448-
for seed in native_field(project, "seeds")?.try_iter()? {
446+
for seed in project_reads::seeds(project)?.try_iter()? {
449447
let seed = seed?;
450448
if wanted.contains(native_field(&seed, field)?)? {
451449
entries.push(seed_entry(&seed)?);
@@ -460,7 +458,7 @@ fn origin_model_entries<'py>(
460458
) -> PyResult<Bound<'py, PyAny>> {
461459
let py = project.py();
462460
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
463-
for model in native_field(project, "models")?.try_iter()? {
461+
for model in project_reads::models(project)?.try_iter()? {
464462
let model = model?;
465463
if !selected_names.contains(model_reads::name_object(&model)?)? || disabled_model(&model)? {
466464
continue;
@@ -487,7 +485,7 @@ fn origin_source_entries<'py>(
487485
let py = project.py();
488486
let mut keys: Vec<Bound<'py, PyAny>> = Vec::new();
489487
let mut order: Vec<Bound<'py, PyAny>> = Vec::new();
490-
for source in native_field(project, "sources")?.try_iter()? {
488+
for source in project_reads::sources(project)?.try_iter()? {
491489
let source = source?;
492490
if selected_names.contains(native_field(&source, "name")?)? {
493491
keys.push(native_field(&source, "key")?);

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/command_plans.rs‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
44
use crate::bindings::_helpers::boundary::python_calls::keywords;
55
use crate::bindings::_helpers::compiled_views::model_reads;
6+
use crate::bindings::_helpers::compiled_views::project_reads;
67
use crate::bindings::_helpers::fingerprints::storage_io::read_latest_fingerprints;
78
use crate::bindings::_helpers::planner_entries::models::RelationsRequest;
89
use crate::bindings::_helpers::planner_entries::plan_output::{
@@ -159,7 +160,7 @@ pub(crate) fn build_audit_command_plan<'py>(
159160
) -> PyResult<Bound<'py, PyAny>> {
160161
let py = project.py();
161162
let materializations = PyDict::new(py);
162-
for model in native_field(project, "models")?.try_iter()? {
163+
for model in project_reads::models(project)?.try_iter()? {
163164
let model = model?;
164165
materializations.set_item(
165166
model_reads::name_object(&model)?,
@@ -200,7 +201,7 @@ fn called_function_keys<'py>(
200201
) -> PyResult<Bound<'py, PySet>> {
201202
let py: Python<'py> = project.py();
202203
let functions: Bound<'py, PyDict> = PyDict::new(py);
203-
for function in native_field(project, "functions")?.try_iter()? {
204+
for function in project_reads::functions(project)?.try_iter()? {
204205
let function = function?;
205206
functions.set_item(native_field(&function, "key")?, function)?;
206207
}
@@ -254,7 +255,7 @@ pub(crate) fn build_test_command_plan<'py>(
254255
)?;
255256
let (entries, warnings) = (selected.entries, selected.warnings);
256257
let mut case_names: BTreeSet<String> = BTreeSet::new();
257-
for test in native_field(&project, "sql_tests")?.try_iter()? {
258+
for test in project_reads::sql_tests(&project)?.try_iter()? {
258259
let test = test?;
259260
let case_name = native_field(&test, "case_name")?;
260261
if !case_name.is_none() && test_selected(&test, &selected_keys, &selection)? {
@@ -271,7 +272,7 @@ pub(crate) fn build_test_command_plan<'py>(
271272
}
272273
let function_keys = called_function_keys(&project, function_keys)?;
273274
let mut functions: Vec<Bound<'py, PyAny>> = Vec::new();
274-
for function in native_field(&project, "functions")?.try_iter()? {
275+
for function in project_reads::functions(&project)?.try_iter()? {
275276
let function = function?;
276277
if !function_keys.contains(native_field(&function, "key")?)? {
277278
continue;
@@ -331,7 +332,7 @@ pub(crate) fn build_seed_command_plan<'py>(
331332
};
332333
let selected_keys = native_field(scope, "selected_keys")?;
333334
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
334-
for seed in native_field(project, "seeds")?.try_iter()? {
335+
for seed in project_reads::seeds(project)?.try_iter()? {
335336
let seed = seed?;
336337
if !selected_keys.contains(native_field(&seed, "key")?)? {
337338
continue;

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/display_plan.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Display-only plans for external plan surfaces when warehouse planning cannot resolve.
22
33
use crate::bindings::_helpers::compiled_views::model_reads;
4+
use crate::bindings::_helpers::compiled_views::project_reads;
45
use crate::bindings::_helpers::model_config::typed_config::{config_text_object, model_values};
56
use crate::bindings::_helpers::planner_entries::values::{
67
boolean, native, none, planner_model, planner_type, string,
@@ -138,7 +139,7 @@ pub(crate) fn build_display_only_sqlbuild_plan<'py>(
138139
.collect::<PyResult<Vec<_>>>()?,
139140
)?;
140141
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
141-
for model in native_field(project, "models")?.try_iter()? {
142+
for model in project_reads::models(project)?.try_iter()? {
142143
let model = model?;
143144
if selected.contains(model_reads::name_object(&model)?)? {
144145
entries.push(display_entry(&model, full_refresh)?);

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/model_entries.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
44
use crate::bindings::_helpers::boundary::python_calls::keywords;
55
use crate::bindings::_helpers::compiled_views::model_reads;
6+
use crate::bindings::_helpers::compiled_views::project_reads;
67
use crate::bindings::_helpers::discovery::guidance::microbatch_guidance;
78
use crate::bindings::_helpers::planner_changes::actions::replaces_incremental_relation;
89
use crate::bindings::_helpers::planner_changes::detect::detect_model_changes;
@@ -426,7 +427,7 @@ pub(crate) fn plan_entries<'py>(
426427
runtime_cursor_producer_names(&scope, &relations_context.source_map.bind(py).clone())?,
427428
)?;
428429
let functions_by_name = PyDict::new(py);
429-
for function in native_field(&project, "functions")?.try_iter()? {
430+
for function in project_reads::functions(&project)?.try_iter()? {
430431
let function = function?;
431432
functions_by_name.set_item(native_field(&function, "name")?, function)?;
432433
}

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/plan_output.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
44
use crate::bindings::_helpers::boundary::python_calls::keywords;
5+
use crate::bindings::_helpers::compiled_views::project_reads;
56
use crate::bindings::_helpers::planner_entries::model_entries::scope_overlaps;
67
use crate::bindings::_helpers::planner_entries::models::PlanOutputInputs;
78
use crate::bindings::_helpers::planner_entries::values::{
@@ -104,7 +105,7 @@ fn seed_entries<'py>(
104105
let metadata_jsons = native_field(extras, "seed_metadata_jsons")?;
105106
let plan_reasons = native_field(extras, "seed_plan_reasons")?;
106107
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
107-
for seed in native_field(project, "seeds")?.try_iter()? {
108+
for seed in project_reads::seeds(project)?.try_iter()? {
108109
let seed = seed?;
109110
if !selected_keys.contains(native_field(&seed, "key")?)? {
110111
continue;
@@ -404,7 +405,7 @@ fn function_entries<'py>(
404405
let functions = native_field(changes, "functions")?;
405406
let previous = native_field(&native_field(snapshot, "fingerprints")?, "functions")?;
406407
let mut entries: Vec<Bound<'py, PyAny>> = Vec::new();
407-
for function in native_field(project, "functions")?.try_iter()? {
408+
for function in project_reads::functions(project)?.try_iter()? {
408409
let function = function?;
409410
if !selected_keys.contains(native_field(&function, "key")?)? {
410411
continue;
@@ -464,7 +465,7 @@ pub(super) fn selected_test_entries<'py>(
464465
) -> PyResult<SelectedTests<'py>> {
465466
let py = project.py();
466467
let mut selected: Vec<Bound<'py, PyAny>> = Vec::new();
467-
for test in native_field(project, "sql_tests")?.try_iter()? {
468+
for test in project_reads::sql_tests(project)?.try_iter()? {
468469
let test = test?;
469470
if !test_selected(&test, selected_keys, selection)? {
470471
continue;

‎crates/sqlbuild-python/src/bindings/_helpers/planner_entries/relations.rs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
44
use crate::bindings::_helpers::boundary::python_calls::keywords;
5+
use crate::bindings::_helpers::compiled_views::project_reads;
56
use crate::bindings::_helpers::planner_entries::models::{
67
PlannerRelationsContext, RelationsRequest,
78
};
@@ -31,7 +32,7 @@ fn selected_audit_relation_keys<'py>(
3132
) -> PyResult<Bound<'py, PyAny>> {
3233
let py = project.py();
3334
let keys = PySet::empty(py)?;
34-
for audit in native_field(project, "audits")?.try_iter()? {
35+
for audit in project_reads::audits(project)?.try_iter()? {
3536
let audit = audit?;
3637
if audit_is_selected(&audit, selected_keys)? {
3738
for dependency in native_field(&audit, "scope_deps")?.try_iter()? {
@@ -99,12 +100,12 @@ pub(crate) fn planner_relations_context<'py>(
99100
let selected_keys = native_field(&scope, "selected_keys")?;
100101
let mut model_locations = object(
101102
py,
102-
build_model_locations(&native_field(&project, "models")?)?,
103+
build_model_locations(&project_reads::models(&project)?)?,
103104
)?;
104-
let mut seed_locations = object(py, build_seed_locations(&native_field(&project, "seeds")?)?)?;
105+
let mut seed_locations = object(py, build_seed_locations(&project_reads::seeds(&project)?)?)?;
105106
let function_locations = object(
106107
py,
107-
build_function_locations(&native_field(&project, "functions")?)?,
108+
build_function_locations(&project_reads::functions(&project)?)?,
108109
)?;
109110
let deferred_locations = native_field(&deferral, "deferred_locations")?;
110111
if !deferred_locations.is_none() {

‎crates/sqlbuild-python/src/bindings/_helpers/planner_identity/graph.rs‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use sqlbuild_analysis::planner_identity::main::topological_order::topological_or
2020
use sqlbuild_analysis::planner_identity::models::{AvailableUpstreams, GraphKey, MissingUpstream};
2121

2222
use crate::bindings::_helpers::boundary::python_calls::KeywordArguments;
23+
use crate::bindings::_helpers::compiled_views::project_reads;
2324
use crate::bindings::_helpers::graph::algorithms::{closure, inverted};
2425
use crate::bindings::_helpers::graph::keys::KeyCache;
2526
use crate::bindings::_helpers::planner_identity::hashing::graph_key;
@@ -89,8 +90,14 @@ pub(crate) fn build_execution_upstream_deps<'py>(
8990
) -> PyResult<Bound<'py, PyDict>> {
9091
let py: Python<'py> = project.py();
9192
let upstream: Bound<'py, PyDict> = PyDict::new(py);
92-
for collection in ["models", "sources", "seeds", "functions"] {
93-
for resource in native_field(project, collection)?.try_iter()? {
93+
let collections: [Bound<'py, PyAny>; 4] = [
94+
project_reads::models(project)?,
95+
project_reads::sources(project)?,
96+
project_reads::seeds(project)?,
97+
project_reads::functions(project)?,
98+
];
99+
for collection in collections {
100+
for resource in collection.try_iter()? {
94101
let resource: Bound<'py, PyAny> = resource?;
95102
upstream.set_item(
96103
native_field(&resource, "key")?,
@@ -103,7 +110,7 @@ pub(crate) fn build_execution_upstream_deps<'py>(
103110
)?;
104111
}
105112
}
106-
for test in native_field(project, "sql_tests")?.try_iter()? {
113+
for test in project_reads::sql_tests(project)?.try_iter()? {
107114
let test: Bound<'py, PyAny> = test?;
108115
let test_key: Bound<'py, PyAny> = native_field(&test, "key")?;
109116
let scope_deps: Bound<'py, PyAny> = native_field(&test, "scope_deps")?;
@@ -172,7 +179,7 @@ pub(crate) fn build_execution_edge_origins<'py>(
172179
) -> PyResult<Bound<'py, PyDict>> {
173180
let py: Python<'py> = project.py();
174181
let origins: Bound<'py, PyDict> = PyDict::new(py);
175-
for test in native_field(project, "sql_tests")?.try_iter()? {
182+
for test in project_reads::sql_tests(project)?.try_iter()? {
176183
let test: Bound<'py, PyAny> = test?;
177184
let test_name: String = native_field(&test, "name")?.extract()?;
178185
for target_key in native_field(&test, "scope_deps")?.try_iter()? {

0 commit comments

Comments
 (0)