diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 477b06fe62..c0cff908c0 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -96,7 +96,7 @@ jobs: ;; esac case "${path}" in - scripts/compiler_differential/*|scripts/run_compiler_differential.py|tests/*/scripts/compiler_differential/*|.github/workflows/verify.yml|Makefile) + scripts/compiler_differential/*|scripts/run_compiler_differential.py|tests/*/scripts/compiler_differential/*|tests/goldens/*|tests/e2e/fixtures/*|website/examples/*|src/sqlbuild/cli/commands/_helpers/compile/*|.github/workflows/verify.yml|Makefile) compiler_differential=true ;; esac @@ -318,7 +318,7 @@ jobs: path: ${{ runner.temp }}/compiler-differential-wheel-sites.json if-no-files-found: warn retention-days: 30 - - name: Compare generated seeds and the failure corpus (python vs shipped native) + - name: Compare fixtures, examples, generated seeds and the failure corpus (python vs shipped native) run: >- make compiler-differential-shipped COMPILER_DIFFERENTIAL_ARGS="--stage-captures --require-discovery-coverage @@ -595,7 +595,7 @@ jobs: run: make test-e2e-diagnostic-compile-performance compile_performance_ratio: - name: Same-runner compile ratio (${{ matrix.kind }} 3000 models) + name: Same-runner compile ratio (${{ matrix.label || matrix.kind }} 3000 models) needs: [changes, lockfile] if: needs.changes.outputs.performance == 'true' runs-on: ubuntu-24.04 @@ -608,6 +608,25 @@ jobs: max_ratio: "1.10" - kind: fresh max_ratio: "1.10" + - kind: dense + label: native-preview contracts vs python + base_engine: python + head_engine: native-preview + gate_phase: contracts_cpu_ms + max_ratio: "1.00" + - kind: dense + label: native-preview model analysis vs python + base_engine: python + head_engine: native-preview + gate_phase: model_analysis_cpu_ms + compile_args: --compile-arg=--select=* + max_ratio: "1.50" + - kind: dense + label: native-preview custom rules vs python + base_engine: python + head_engine: native-preview + gate_phase: custom_rules_cpu_ms + max_ratio: "1.25" steps: - uses: actions/checkout@v4 - name: Check out the comparison base @@ -634,7 +653,29 @@ jobs: - name: Install base dependencies working-directory: base run: uv sync --locked --all-groups --all-extras + - name: Compare python and native-preview phase CPU on head + if: matrix.gate_phase + env: + KIND: ${{ matrix.kind }} + MAX_RATIO: ${{ matrix.max_ratio }} + BASE_ENGINE: ${{ matrix.base_engine }} + HEAD_ENGINE: ${{ matrix.head_engine }} + GATE_PHASE: ${{ matrix.gate_phase }} + COMPILE_ARGS: ${{ matrix.compile_args }} + run: | + uv run python -m scripts.compare_compile_performance \ + --kind "${KIND}" \ + --modes cold \ + --max-ratio "${MAX_RATIO}" \ + --models 3000 \ + --base-python .venv/bin/python \ + --head-python .venv/bin/python \ + --base-engine "${BASE_ENGINE}" \ + --head-engine "${HEAD_ENGINE}" \ + --gate-phase "${GATE_PHASE}" \ + ${COMPILE_ARGS:+"${COMPILE_ARGS}"} - name: Compare base and head cold, warm and one-model edit compiles + if: ${{ !matrix.gate_phase }} env: KIND: ${{ matrix.kind }} MAX_RATIO: ${{ matrix.max_ratio }} diff --git a/Makefile b/Makefile index 8512fc21b1..2d119c858e 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ SHELL := /bin/bash test-e2e-duckdb-integrations test-e2e-performance \ test-e2e-cold-compile-performance test-e2e-cache-compile-performance \ test-e2e-dense-compile-performance test-e2e-varied-cache-performance \ - compiler-differential compiler-differential-shipped compiler-differential-dense + compiler-differential compiler-differential-shipped compiler-differential-dense \ + compiler-baselines format: uv run ruff format . @@ -293,19 +294,32 @@ COMPILER_DIFFERENTIAL_SEEDS ?= 12 COMPILER_DIFFERENTIAL_SHIPPED_SEEDS ?= 12 COMPILER_DIFFERENTIAL_DENSE_MODELS ?= 3000 COMPILER_DIFFERENTIAL_ARGS ?= +# Native-to-Python fallbacks and analysis deferrals must match the allow-list exactly, and every +# output its golden. `make compiler-baselines` rewrites both (see scripts/compiler_differential/README.md). +COMPILER_DIFFERENTIAL_GATES := --native-fallbacks check --goldens check compiler-differential: env PYTHONUNBUFFERED=1 uv run python -m scripts.run_compiler_differential \ --jobs $(COMPILER_DIFFERENTIAL_JOBS) --seeds $(COMPILER_DIFFERENTIAL_SEEDS) \ - $(COMPILER_DIFFERENTIAL_ARGS) + $(COMPILER_DIFFERENTIAL_GATES) $(COMPILER_DIFFERENTIAL_ARGS) # python vs native-preview above covers every native stage; this keeps the shipped `native` default -# (native discovery and rendering) covered on a bounded corpus. +# (native discovery and rendering) and its goldens covered on the same corpus. compiler-differential-shipped: env PYTHONUNBUFFERED=1 uv run python -m scripts.run_compiler_differential \ - --engines python native --corpus seeds failures \ + --engines python native --corpus fixtures examples seeds failures \ --jobs $(COMPILER_DIFFERENTIAL_JOBS) --seeds $(COMPILER_DIFFERENTIAL_SHIPPED_SEEDS) \ - $(COMPILER_DIFFERENTIAL_ARGS) + $(COMPILER_DIFFERENTIAL_GATES) $(COMPILER_DIFFERENTIAL_ARGS) + +# Rewrite the goldens (from the python oracle) and the fallback allow-list from both CI runs. +# Review the diff like code; see scripts/compiler_differential/README.md. +COMPILER_DIFFERENTIAL_CI_ARGS := --stage-captures --require-discovery-coverage --require-render-coverage +compiler-baselines: + rm -rf tests/goldens/compiler + $(MAKE) compiler-differential COMPILER_DIFFERENTIAL_ARGS="$(COMPILER_DIFFERENTIAL_CI_ARGS) \ + --require-analysis-coverage --native-fallbacks update --goldens update" + $(MAKE) compiler-differential-shipped COMPILER_DIFFERENTIAL_ARGS="$(COMPILER_DIFFERENTIAL_CI_ARGS) \ + --native-fallbacks update --goldens update" compiler-differential-dense: env PYTHONUNBUFFERED=1 uv run python -m scripts.run_compiler_differential \ diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/catalog_state.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/catalog_state.rs index a72ed4906b..0bbe164e2e 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/catalog_state.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/catalog_state.rs @@ -17,6 +17,10 @@ pub(crate) struct SessionCatalog { additions: Shapes, analysis_names: Vec, recorded_analysis: HashSet, + /// The `(types, nullability)` this session gave each relation's analysis. + analysis_shapes: HashMap, + pub(crate) shared_members: usize, + pub(crate) reanalysed_members: usize, } impl SessionCatalog { @@ -28,6 +32,9 @@ impl SessionCatalog { additions: Vec::new(), analysis_names: Vec::new(), recorded_analysis: HashSet::new(), + analysis_shapes: HashMap::new(), + shared_members: 0, + reanalysed_members: 0, } } @@ -86,6 +93,8 @@ impl SessionCatalog { name.clone(), (catalog_columns(&column_types), catalog_columns(columns)), ); + self.analysis_shapes + .insert(name.clone(), (column_types, columns.clone())); if self.recorded_analysis.insert(name.clone()) { self.analysis_names.push(name.clone()); } @@ -95,6 +104,27 @@ impl SessionCatalog { } } + /// `(shared members, shared members re-analysed alone)` so far. + pub(crate) fn sharing(&self) -> (usize, usize) { + (self.shared_members, self.reanalysed_members) + } + + /// The analysis shape this session set for `name`; inherited shapes are not known here. + pub(crate) fn session_analysis_shape(&self, name: &str) -> Option<&(Pairs, Pairs)> { + self.analysis_shapes.get(name) + } + + /// The shape a binding of `columns` for `name` resolves: Python's override or catalog entry. + pub(crate) fn effective_binding_shape(&self, name: &str, columns: &Pairs) -> Pairs { + if columns.is_empty() { + return Vec::new(); + } + match self.schemas.get(name) { + Some(known) if same_mapping(known, columns) => known.clone(), + _ => columns.clone(), + } + } + pub(crate) fn register_override(&mut self, overrides: Relations) -> usize { self.native.register_override(overrides) } diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/compact_batch.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/compact_batch.rs index 5a3b0bd450..4b5186a968 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/compact_batch.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/compact_batch.rs @@ -1,26 +1,33 @@ -//! One compact analysis batch built, run and projected exactly as Python's unshared batch. +//! One compact analysis batch built, shared, run and projected exactly as Python's batch. use std::collections::{HashMap, HashSet}; +use std::sync::LazyLock; +use regex::{Captures, Regex}; use serde_json::{Map, Value, json}; use crate::assembly::analysis_session::_helpers::catalog_state::SessionCatalog; use crate::assembly::analysis_session::_helpers::mappings::{ShapeTable, native_dialect}; use crate::assembly::analysis_session::constants::{ BINDING_SEVERITIES, COMPACT_WORKERS, CONFIDENCE_CODES, DEFAULT_BINDING_MESSAGE, FACT_LENGTH, - INVALID_NATIVE_RESPONSE, LEGACY_FALLBACK, LEGACY_RESPONSE_LENGTH, NULLABILITY_BY_CODE, - RESPONSE_LENGTH, SOURCE_LENGTH, TRANSFORM_CODES, + INVALID_NATIVE_RESPONSE, LEGACY_FALLBACK, LEGACY_RESPONSE_LENGTH, MIN_SHARED_MEMBERS, + NULLABILITY_BY_CODE, PYTHON_ASCII_SPACES, QUALIFIED_SCAN_TOKENS, REFERENCE_MARKER_PATTERN, + RELATION_STUB_PREFIX, RESPONSE_LENGTH, SOURCE_LENGTH, TRANSFORM_CODES, + UNSTUBBED_REFERENCE_KIND, }; use crate::assembly::analysis_session::models::{ColumnFact, LineageRow}; use crate::assembly::analysis_session::types::{Pairs, Shapes}; use crate::semantic_validation::main::diagnostics::binding_diagnostics; -use crate::semantic_validation::types::{DiagnosticRow, NormalizationRequest}; +use crate::semantic_validation::types::{DiagnosticRow, NormalizationRequest, Relations}; const INVALID_BATCH: &str = "native compact query analysis returned an invalid batch response"; const INVALID_TEMPLATE: &str = "native compact query analysis returned an invalid template"; const INVALID_COLUMN: &str = "native compact analysis returned invalid column facts"; +static REFERENCE_MARKER: LazyLock> = + LazyLock::new(|| Regex::new(REFERENCE_MARKER_PATTERN).map_err(|error| error.to_string())); /// One query of a batch with the facts Python's preparation reads. +#[derive(Clone)] pub(crate) struct BatchMember<'a> { pub(crate) query_sql: &'a str, pub(crate) placeholders: &'a Pairs, @@ -73,10 +80,31 @@ struct BatchResponse<'a> { templates: &'a [Value], } -/// The prepared request and each member's query index. +/// The prepared request, each member's query index and the queries members share. struct BatchPayload { request: Value, query_indexes: Vec, + shared_queries: HashSet, +} + +/// Python's `SharedBindingQuery`: one member's relation-stubbed query and its identity. +struct SharedQuery { + sql: String, + /// Each lineage reference's stub, in reference order. + stubs: Vec<(String, String)>, + key: String, +} + +impl SharedQuery { + fn stub<'a>(&'a self, name: &'a str) -> &'a str { + stub_name(&self.stubs, name) + } +} + +/// One run's projected members and the shared members whose result Python recomputes. +struct BatchRun { + results: Vec, + inexact: Vec, } impl SessionCatalog { @@ -98,20 +126,203 @@ impl SessionCatalog { } self.prepare_analysis(&required, batch.types, batch.nullability); let cleaned: Vec = self.normalize_members(batch)?; - let payload: BatchPayload = self.batch_payload(batch, &cleaned)?; + let shared: Vec> = self.shared_queries(batch, &cleaned)?; + let BatchRun { + mut results, + inexact, + } = self.run_batch(batch, cleaned, &shared)?; + self.shared_members += shared.iter().flatten().count(); + self.reanalysed_members += inexact.len(); + if !inexact.is_empty() { + let subset = Batch { + members: inexact + .iter() + .map(|index| batch.members[*index].clone()) + .collect(), + ..*batch + }; + let cleaned: Vec = inexact + .iter() + .map(|index| results[*index].cleaned_sql.clone()) + .collect(); + let unshared: Vec> = inexact.iter().map(|_| None).collect(); + let rerun: BatchRun = self.run_batch(&subset, cleaned, &unshared)?; + for (index, result) in inexact.into_iter().zip(rerun.results) { + results[index] = result; + } + } + self.with_separate_validation(&batch.members, results) + } + + /// Python's `_analyze_compact_inputs` run: prepare, analyse, project and find inexact sharing. + fn run_batch( + &mut self, + batch: &Batch<'_>, + cleaned: Vec, + shared: &[Option], + ) -> Result { + let payload: BatchPayload = self.batch_payload(batch, &cleaned, shared)?; let job = self.native.prepare_compact(&payload.request.to_string())?; let analysis = job .take_analysis() .ok_or("compact analysis job already ran")?; let response: Value = serde_json::from_str(&job.run(analysis)?).map_err(|error| error.to_string())?; + let inexact: Vec = inexact_shared_members(&response, &payload); let results: Vec = attach_validations( &response, &payload.query_indexes, batch.dialect, project_response(&response, cleaned)?, )?; - self.with_separate_validation(&batch.members, results) + Ok(BatchRun { results, inexact }) + } + + /// Python's `prepare_binding_queries` shared forms, for keys at least two members match. + fn shared_queries( + &self, + batch: &Batch<'_>, + cleaned: &[String], + ) -> Result>, String> { + let prekeys: Vec> = batch + .members + .iter() + .map(member_prekey) + .collect::>()?; + let mut prekey_counts: HashMap<&str, usize> = HashMap::new(); + for prekey in prekeys.iter().flatten() { + *prekey_counts.entry(prekey.as_str()).or_default() += 1; + } + let mut candidates: Vec<(usize, Vec<(String, String)>)> = Vec::new(); + for (index, (member, prekey)) in batch.members.iter().zip(&prekeys).enumerate() { + let (Some(schema), Some(prekey)) = (member.binding_schema, prekey) else { + continue; + }; + if prekey_counts.get(prekey.as_str()).copied().unwrap_or(0) < MIN_SHARED_MEMBERS { + continue; + } + if let Some(names) = self.shared_reference_names(&cleaned[index], member, schema) { + let stubs: Vec<(String, String)> = names + .into_iter() + .enumerate() + .map(|(position, name)| (name, format!("{RELATION_STUB_PREFIX}{position}"))) + .collect(); + candidates.push((index, stubs)); + } + } + let requests: Vec = candidates + .iter() + .map(|(index, stubs)| { + let member: &BatchMember<'_> = &batch.members[*index]; + ( + member.query_sql.to_owned(), + stubs.iter().cloned().collect(), + member.placeholders.iter().cloned().collect(), + ) + }) + .collect(); + let stubbed: Vec> = if requests.is_empty() { + Vec::new() + } else { + self.native + .normalize_analysis_sqls(batch.dialect, requests)? + }; + let mut shared: Vec> = batch.members.iter().map(|_| None).collect(); + for ((index, stubs), sql) in candidates.into_iter().zip(stubbed) { + let (Ok(sql), Some(schema)) = (sql, batch.members[index].binding_schema) else { + continue; + }; + let key: String = self.shared_key( + batch.dialect, + &sql, + &stubs, + (schema, batch.members[index].recover_cte_facts), + ); + shared[index] = Some(SharedQuery { sql, stubs, key }); + } + let mut key_counts: HashMap = HashMap::new(); + for query in shared.iter().flatten() { + *key_counts.entry(query.key.clone()).or_default() += 1; + } + Ok(shared + .into_iter() + .map(|query| with_partner(query, &key_counts)) + .collect()) + } + + /// Python's `_shared_reference_names`, None where stubbing could change the analysis. + fn shared_reference_names( + &self, + cleaned_sql: &str, + member: &BatchMember<'_>, + schema: &Shapes, + ) -> Option> { + let names: Vec = member + .lineage_references + .iter() + .map(|(name, _, _)| name.clone()) + .collect(); + let folded: HashSet = names.iter().map(|name| name.to_lowercase()).collect(); + let plain_text: bool = cleaned_sql.is_ascii() && names.iter().all(|name| name.is_ascii()); + let quoted: bool = cleaned_sql.contains('"') || schema_quoted(schema); + let collides: bool = names + .iter() + .any(|name| name.starts_with(RELATION_STUB_PREFIX)) + || cleaned_sql + .to_ascii_lowercase() + .contains(RELATION_STUB_PREFIX); + let unshaped: bool = names + .iter() + .any(|name| self.session_analysis_shape(name).is_none()); + let usable: bool = !names.is_empty() + && folded.len() == names.len() + && plain_text + && !quoted + && !collides + && !unshaped + && !names_qualify(cleaned_sql, &names); + usable.then_some(names) + } + + /// Python's `SharedBindingQuery.key`, with the CTE fact flag its query key adds. + fn shared_key( + &self, + dialect: &str, + sql: &str, + stubs: &[(String, String)], + (schema, recover_cte_facts): (&Shapes, bool), + ) -> String { + let analysis_shapes: Vec = stubs + .iter() + .map(|(name, stub)| { + let (types, nullability) = self + .session_analysis_shape(name) + .cloned() + .unwrap_or_default(); + json!([stub, types, nullability]) + }) + .collect(); + let mut binding_shapes: Vec = schema + .iter() + .map(|(relation, columns)| { + let alias: &str = stub_name(stubs, relation); + json!([ + alias, + !columns.is_empty(), + self.effective_binding_shape(relation, columns) + ]) + .to_string() + }) + .collect(); + binding_shapes.sort_unstable(); + json!([ + sql, + dialect, + analysis_shapes, + binding_shapes, + recover_cte_facts + ]) + .to_string() } fn normalize_members(&self, batch: &Batch<'_>) -> Result, String> { @@ -137,6 +348,7 @@ impl SessionCatalog { &mut self, batch: &Batch<'_>, cleaned: &[String], + shared: &[Option], ) -> Result { let function_return_types: Map = batch .function_return_types @@ -145,20 +357,40 @@ impl SessionCatalog { .collect(); let mut queries: Vec = Vec::new(); let mut query_keys: HashMap = HashMap::new(); + let mut shared_queries: HashSet = HashSet::new(); let mut templates: Vec = Vec::new(); let mut template_keys: HashMap = HashMap::new(); let mut projections: Vec = Vec::with_capacity(batch.members.len()); let mut query_indexes: Vec = Vec::with_capacity(batch.members.len()); - for (member, sql) in batch.members.iter().zip(cleaned) { - let query: Value = self.member_query(batch.dialect, member, sql)?; - let query_index: usize = *query_keys.entry(query.to_string()).or_insert_with(|| { - queries.push(query); - queries.len() - 1 - }); + for ((member, sql), share) in batch.members.iter().zip(cleaned).zip(shared) { + let query_index: usize = match share { + Some(share) => { + let binding = self.member_binding(member, sql)?; + let index: usize = match query_keys.get(&share.key) { + Some(index) => *index, + None => { + let query: Value = + self.shared_member_query(batch.dialect, member, share, binding); + queries.push(query); + query_keys.insert(share.key.clone(), queries.len() - 1); + queries.len() - 1 + } + }; + shared_queries.insert(index); + index + } + None => { + let query: Value = self.member_query(batch.dialect, member, sql)?; + *query_keys.entry(query.to_string()).or_insert_with(|| { + queries.push(query); + queries.len() - 1 + }) + } + }; query_indexes.push(query_index); let template: Value = json!({ "queryIndex": query_index, - "references": lineage_resources(member), + "references": lineage_resources(member, share.as_ref()), "functionReturnTypes": function_return_types, "declaredColumnOrder": declared_column_order(member, batch.nullability), "recoverCteFacts": member.recover_cte_facts, @@ -174,7 +406,12 @@ impl SessionCatalog { let resource_names: Map = member .lineage_references .iter() - .map(|(name, _, resource)| (name.clone(), Value::String(resource.clone()))) + .map(|(name, _, resource)| { + let canonical: &str = share + .as_ref() + .map_or(name.as_str(), |share| share.stub(name)); + (canonical.to_owned(), Value::String(resource.clone())) + }) .collect(); projections .push(json!({"templateIndex": template_index, "resourceNames": resource_names})); @@ -187,9 +424,64 @@ impl SessionCatalog { "workers": COMPACT_WORKERS, }), query_indexes, + shared_queries, }) } + /// A bound member's sorted binding references and overrides, preparing its relations. + fn member_binding( + &mut self, + member: &BatchMember<'_>, + sql: &str, + ) -> Result<(Vec<(String, bool)>, Relations), String> { + let schema: &Shapes = member + .binding_schema + .ok_or("a shared member has no binding schema")?; + let (_, references, overrides) = self + .prepare(&[(sql, schema)]) + .pop() + .ok_or("binding preparation returned no request")?; + Ok((references, overrides)) + } + + /// Python's shared query: stubbed SQL with references, aliases and binding sorted by stub. + fn shared_member_query( + &mut self, + dialect: &str, + member: &BatchMember<'_>, + share: &SharedQuery, + (references, overrides): (Vec<(String, bool)>, Relations), + ) -> Value { + let mut lineage_names: Vec<&str> = member + .lineage_references + .iter() + .map(|(name, _, _)| name.as_str()) + .collect(); + lineage_names.sort_by_key(|name| share.stub(name)); + let analysis_references: Vec<[&str; 2]> = lineage_names + .iter() + .map(|name| [*name, share.stub(name)]) + .collect(); + let mut references: Vec<(String, bool)> = references; + references.sort_by(|(left, _), (right, _)| share.stub(left).cmp(share.stub(right))); + let aliases: Map = references + .iter() + .filter(|(name, _)| share.stub(name) != name.as_str()) + .map(|(name, _)| (name.clone(), Value::String(share.stub(name).to_owned()))) + .collect(); + let mut query: Value = json!({ + "sql": share.sql, + "dialect": dialect, + "analysis_references": analysis_references, + "binding_references": references, + "binding_aliases": aliases, + }); + if !overrides.is_empty() { + query["binding_override"] = json!(self.register_override(overrides)); + } + query + } + /// One member's query: analysis references and, when bound, its catalog binding. fn member_query( &mut self, @@ -260,19 +552,187 @@ impl SessionCatalog { } } -fn lineage_resources(member: &BatchMember<'_>) -> Map { +fn lineage_resources(member: &BatchMember<'_>, share: Option<&SharedQuery>) -> Map { member .lineage_references .iter() .map(|(name, resource_type, _)| { + let canonical: &str = share.map_or(name.as_str(), |share| share.stub(name)); ( - name.clone(), - json!({"resourceType": resource_type, "resourceName": name}), + canonical.to_owned(), + json!({"resourceType": resource_type, "resourceName": canonical}), ) }) .collect() } +/// Python's `binding_share_prekey`: authored SQL with lineage reference markers as stubs. +fn share_prekey(member: &BatchMember<'_>) -> Result { + let marker: &Regex = REFERENCE_MARKER.as_ref().map_err(Clone::clone)?; + let positions: HashMap<&str, usize> = member + .lineage_references + .iter() + .enumerate() + .map(|(position, (name, _, _))| (name.as_str(), position)) + .collect(); + Ok(marker + .replace_all(member.query_sql, |captures: &Captures<'_>| { + let whole: &str = captures.get(0).map_or("", |found| found.as_str()); + let kind: &str = captures.get(1).map_or("", |found| found.as_str()); + match captures + .get(2) + .and_then(|found| positions.get(found.as_str())) + { + Some(position) if kind != UNSTUBBED_REFERENCE_KIND => { + format!("{RELATION_STUB_PREFIX}{position}") + } + _ => whole.to_owned(), + } + }) + .into_owned()) +} + +/// Python's `_qualified_reference_names` is non-empty; text its scanner reads counts as qualified. +fn names_qualify(sql: &str, names: &[String]) -> bool { + if !sql.contains('.') { + return false; + } + if !sql.is_ascii() + || QUALIFIED_SCAN_TOKENS + .iter() + .any(|token| sql.contains(token)) + { + return true; + } + let folded: String = sql.to_ascii_lowercase(); + names.iter().any(|name| { + let name: String = name.to_lowercase(); + plain_identifier(&name) && is_qualifier(&folded, &name) + }) +} + +/// Python's `_PLAIN_IDENTIFIER_PATTERN`. +fn plain_identifier(name: &str) -> bool { + let mut characters = name.chars(); + characters + .next() + .is_some_and(|first| first.is_ascii_lowercase() || first == '_' || first == '$') + && characters.all(|character| { + character.is_ascii_lowercase() + || character.is_ascii_digit() + || character == '_' + || character == '$' + }) +} + +/// Python's `_is_qualifier`: `name` as a whole identifier followed by `.` after any spaces. +fn is_qualifier(folded_sql: &str, name: &str) -> bool { + let identifier = |byte: u8| byte.is_ascii_alphanumeric() || byte == b'_' || byte == b'$'; + let bytes: &[u8] = folded_sql.as_bytes(); + folded_sql.match_indices(name).any(|(start, _)| { + let mut end: usize = start + name.len(); + let bounded: bool = (start == 0 || !identifier(bytes[start - 1])) + && (end == bytes.len() || !identifier(bytes[end])); + while bounded && end < bytes.len() && PYTHON_ASCII_SPACES.as_bytes().contains(&bytes[end]) { + end += 1; + } + bounded && bytes.get(end) == Some(&b'.') + }) +} + +/// Python's `_inexact_shared_members`: shared members whose result depends on relation names. +fn inexact_shared_members(response: &Value, payload: &BatchPayload) -> Vec { + if payload.shared_queries.is_empty() { + return Vec::new(); + } + let (Some(analyses), Some(templates)) = ( + response.get("analyses").and_then(Value::as_array), + response.get("templates").and_then(Value::as_array), + ) else { + return Vec::new(); + }; + let validations: Option<&Vec> = response.get("validations").and_then(Value::as_array); + payload + .query_indexes + .iter() + .zip(analyses) + .enumerate() + .filter(|(_, (query, analysis))| { + payload.shared_queries.contains(query) && { + let template: Option<&Value> = analysis_template(analysis, templates); + let validation: Option<&Value> = + validations.and_then(|validations| validations.get(**query)); + !shared_result_is_exact(template, validation) + } + }) + .map(|(member, _)| member) + .collect() +} + +/// The template an analysis names, None where Python reads the analysis as a failure. +fn analysis_template<'a>(analysis: &Value, templates: &'a [Value]) -> Option<&'a Value> { + let index: u64 = analysis.as_array()?.first()?.as_u64()?; + match usize::try_from(index) { + Ok(index) => templates.get(index), + Err(_) => None, + } +} + +/// `stubs`' stub for `name`, or `name` itself when it has none. +fn stub_name<'a>(stubs: &'a [(String, String)], name: &'a str) -> &'a str { + for (reference, stub) in stubs { + if reference == name { + return stub; + } + } + name +} + +/// A bound member's prekey; members without a binding schema never share. +fn member_prekey(member: &BatchMember<'_>) -> Result, String> { + match member.binding_schema { + Some(_) => share_prekey(member).map(Some), + None => Ok(None), + } +} + +/// `query` when another member shares its key. +fn with_partner( + query: Option, + counts: &HashMap, +) -> Option { + let query: SharedQuery = query?; + (counts.get(&query.key).copied().unwrap_or(0) >= MIN_SHARED_MEMBERS).then_some(query) +} + +/// Whether a binding relation or column name carries a double quote. +fn schema_quoted(schema: &Shapes) -> bool { + for (relation, columns) in schema { + if relation.contains('"') { + return true; + } + for (column, _) in columns { + if column.contains('"') { + return true; + } + } + } + false +} + +/// Python's `shared_result_is_exact`: an analysed template without any binding diagnostic. +fn shared_result_is_exact(template: Option<&Value>, validation: Option<&Value>) -> bool { + let analysed: bool = template.is_some_and(|template| !template.is_string()); + analysed + && match validation { + None | Some(Value::Null) => true, + Some(validation) => validation + .get("errors") + .and_then(Value::as_array) + .is_some_and(Vec::is_empty), + } +} + /// A single-reference member's declared column order, as Python's template records it. fn declared_column_order<'a>( member: &BatchMember<'_>, diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/cte_facts.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/cte_facts.rs new file mode 100644 index 0000000000..dbb9d925c9 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/cte_facts.rs @@ -0,0 +1,1297 @@ +//! Python's CTE fact recovery and filtered non-null outputs, over the wheel's expression view. + +use std::cell::Cell; +use std::collections::HashSet; +use std::rc::Rc; + +use polyglot_sql::Expression; +use polyglot_sql::traversal::ExpressionWalk; +use serde_json::{Map, Value}; + +use crate::assembly::analysis_session::_helpers::dict_walk::{ + PyValue, alias_or_name, arg, children, column_table_name, direct_tables, expression_args, + find_all, is_star, kind, name, name_payload, output_name, parse_one, projected_expression, + py_truthy, python_int, raw_name_payload, set_operation, to_dict, top_level_ctes, + unwrap_annotations, where_clause, +}; +use crate::assembly::analysis_session::constants::{ + BINARY_OPERAND_COUNT, BOOLEAN_RESULT_AST_KINDS, BOOLEAN_TYPE, CASE_AST_KIND, CAST_AST_KIND, + CAST_AST_KINDS, COALESCE_AST_KIND, COLUMN_AST_KIND, CONCAT_AST_KIND, CONDITIONAL_RESULT_RULE, + COUNT_AST_KIND, CUSTOM_TYPE_NAME, DECIMAL_TYPE, FIRST_ARG_RULE, FUNCTION_AST_KIND, + IF_FUNC_AST_KIND, IS_NULL_AST_KIND, JOIN_FULL, JOIN_LEFT, JOIN_RIGHT, LITERAL_AST_KIND, + NON_NULL_NULLABILITY, NULL_AST_KIND, NULL_SET_OPERATION_TYPE, NULLABLE_NULLABILITY, + NULLIF_FUNCTION_NAME, POLYGLOT_TYPE_NAMES, SELECT_AST_KIND, SET_OPERATION_AST_KINDS, + STRING_LITERAL_TYPE, SUBSTRING_AST_KIND, TABLE_AST_KIND, TEXT_TYPE, TIMESTAMP_TYPE_NAME, + TIMESTAMP_TZ_TYPE, TRY_CAST_AST_KIND, TYPE_PASSTHROUGH_AST_KINDS, UNKNOWN_NULLABILITY, + VARCHAR_DATA_TYPES, WILDCARD, +}; +use crate::assembly::analysis_session::types::{Pairs, Shapes}; +use crate::type_system::main::normalize_type::normalize_type; +use crate::type_system::models::{NormalizedType, TypeFamily}; + +/// A relation's column types; the `Rc` is the identity Python's `id()` dedup compares. +type Shape = Rc; +/// Relation facts in Python dict order. +type Relations = Vec<(String, Shape)>; +/// A relation's column nullabilities. +type NullShape = Rc>; +type NullRelations = Vec<(String, NullShape)>; +/// Python's `NonNullFilterContext`: the selected relations and the proven non-null columns. +type FilterContext = (Vec<(String, NullShape)>, HashSet<(String, String)>); +/// The result of one step, or the reason Python's result is not reproduced. +type Fact = Result; + +/// The inference profile facts the recovery reads. +pub(crate) struct RecoveryProfile<'a> { + pub(crate) dialect: &'a str, + pub(crate) function_return_types: &'a Pairs, + /// Adapter nullability rules by function name; None where a rule is not one Python ships. + pub(crate) rules: Option<&'a Pairs>, +} + +/// One enrichment's recovery request. +pub(crate) struct RecoveryInput<'a> { + pub(crate) cleaned_sql: &'a str, + pub(crate) input_schemas: &'a Shapes, + /// Whether Python runs `_polyglot_cte_passthrough_facts` past its early return. + pub(crate) recover: bool, + /// Whether a filter reads NULL, so Python looks for filtered non-null outputs. + pub(crate) null_filter: bool, + pub(crate) profile: RecoveryProfile<'a>, +} + +/// What Python's compact re-analysis takes from the parsed query. +#[derive(Debug, Default)] +pub(crate) struct Recovery { + pub(crate) types: Vec<(String, String)>, + pub(crate) nullability: Vec<(String, &'static str)>, + pub(crate) direct_outputs: HashSet, + pub(crate) non_null_outputs: HashSet, +} + +/// Python's CTE pass-through facts and filtered non-null outputs, or why they defer. +pub(crate) fn recovery(input: &RecoveryInput<'_>) -> Fact { + NON_ASCII_FOLDED.set(false); + let recovered: Fact = recovered(input); + if NON_ASCII_FOLDED.replace(false) { + return Err("non-ASCII text Python casefolds or upper-cases differently".to_owned()); + } + recovered +} + +thread_local! { + /// Whether this recovery folded non-ASCII text, where Python's `casefold`/`upper` may differ. + static NON_ASCII_FOLDED: Cell = const { Cell::new(false) }; +} + +fn recovered(input: &RecoveryInput<'_>) -> Fact { + let mut recovery: Recovery = Recovery::default(); + let mut parsed: Option> = None; + if input.recover { + let root: Option = parse_one(input.cleaned_sql, input.profile.dialect)?; + if let Some(root) = &root { + recovery = passthrough_facts(root, input, recovery)?; + } + parsed = Some(root); + } + if input.null_filter { + let root: Option = match parsed { + Some(root) => root, + None => parse_one(input.cleaned_sql, input.profile.dialect)?, + }; + if let Some(root) = &root { + recovery.non_null_outputs = filtered_non_null(root, &input_nullability(input))?; + } + } + Ok(recovery) +} + +/// Python's enrichment types: the input shapes. +fn input_types(input: &RecoveryInput<'_>) -> Relations { + input + .input_schemas + .iter() + .map(|(table, shape)| (table.clone(), Rc::new(shape.clone()))) + .collect() +} + +/// Python's enrichment nullability: every input column unknown. +fn input_nullability(input: &RecoveryInput<'_>) -> NullRelations { + input + .input_schemas + .iter() + .map(|(table, shape)| (table.clone(), Rc::new(unknown_columns(shape)))) + .collect() +} + +fn unknown_columns(shape: &Pairs) -> Vec<(String, &'static str)> { + shape + .iter() + .map(|(column, _)| (column.clone(), UNKNOWN_NULLABILITY)) + .collect() +} + +/// Python's `_polyglot_cte_passthrough_facts` after a successful parse. +fn passthrough_facts( + root: &Expression, + input: &RecoveryInput<'_>, + mut recovery: Recovery, +) -> Fact { + let ctes: Vec<(&str, bool, &Expression)> = top_level_ctes(root); + if ctes.is_empty() { + return Ok(recovery); + } + if input.profile.rules.is_none() { + return Err("an adapter nullability rule Python does not ship".to_owned()); + } + let context = Context { + profile: &input.profile, + }; + recovery.types = context.passthrough_types(root, &input_types(input))?; + recovery.nullability = context.passthrough_nullability(root, &input_nullability(input))?; + let names: HashSet = ctes.iter().map(|(name, _, _)| casefold(name)).collect(); + recovery.direct_outputs = direct_cte_outputs(root, &names); + Ok(recovery) +} + +/// Python's `_polyglot_direct_cte_output_names`. +fn direct_cte_outputs(root: &Expression, cte_names: &HashSet) -> HashSet { + let reads_cte: bool = direct_tables(root) + .iter() + .any(|table| cte_names.contains(&casefold(table.get_name()))); + if !reads_cte { + return HashSet::new(); + } + let mut outputs: HashSet = HashSet::new(); + for projection in root.get_expressions() { + let projection: Option<&Expression> = unwrap_annotations(Some(projection)); + if kind(projected_expression(projection)) != COLUMN_AST_KIND { + continue; + } + let output: &str = output_name(projection); + if !output.is_empty() && output != WILDCARD { + outputs.insert(output.to_owned()); + } + } + outputs +} + +/// The profile every resolver reads. +struct Context<'a, 'b> { + profile: &'a RecoveryProfile<'b>, +} + +impl Context<'_, '_> { + /// Python's `_polyglot_cte_passthrough_types_from_parsed`. + fn passthrough_types( + &self, + root: &Expression, + facts: &Relations, + ) -> Fact> { + let ctes: Vec<(&str, bool, &Expression)> = top_level_ctes(root); + if ctes.is_empty() { + return Ok(Vec::new()); + } + let mut relations: Relations = referenced_facts(root, facts); + for (cte_name, has_column_aliases, body) in ctes { + if has_column_aliases { + continue; + } + let inferred: Vec<(String, String)> = + self.select_output_types(Some(body), &relations)?; + if !inferred.is_empty() { + relations = dict_set(relations, cte_name, Rc::new(inferred)); + } + } + if SET_OPERATION_AST_KINDS.contains(&kind(Some(root))) { + return self.set_operation_types(root, &relations); + } + self.direct_select_types(Some(root), &relations) + } + + /// Python's `_polyglot_select_output_types`. + fn select_output_types( + &self, + select: Option<&Expression>, + relations: &Relations, + ) -> Fact> { + let Some(select) = unwrap_annotations(select) else { + return Err("Python reads CTEs of a missing expression".to_owned()); + }; + if !top_level_ctes(select).is_empty() { + return self.passthrough_types(select, relations); + } + if SET_OPERATION_AST_KINDS.contains(&kind(Some(select))) { + return self.set_operation_types(select, relations); + } + self.direct_select_types(Some(select), relations) + } + + /// Python's `_polyglot_set_operation_output_types`. + fn set_operation_types( + &self, + operation: &Expression, + relations: &Relations, + ) -> Fact> { + let Some((left, right, by_name)) = set_operation(operation) else { + return Ok(Vec::new()); + }; + let mut output: Vec<(String, String)> = Vec::new(); + if by_name { + let left_types: Vec<(String, String)> = + self.select_output_types(Some(left), relations)?; + let right_types: Vec<(String, String)> = + self.select_output_types(Some(right), relations)?; + for (name, left_type) in &left_types { + let right_type: Option<&str> = ci_get(&right_types, name).map(String::as_str); + if let Some(common) = self.common_type(Some(left_type), right_type)? { + output = dict_set(output, name, common); + } + } + return Ok(output); + } + let left_slots: Vec = self.type_slots(Some(left), relations)?; + if left_slots.is_empty() { + return Ok(Vec::new()); + } + let right_slots: Vec = self.type_slots(Some(right), relations)?; + if right_slots.is_empty() || left_slots.len() != right_slots.len() { + return Ok(Vec::new()); + } + for ((name, left_type), (_, right_type)) in left_slots.iter().zip(&right_slots) { + if let Some(common) = self.common_type(left_type.as_deref(), right_type.as_deref())? { + output = dict_set(output, name, common); + } + } + Ok(output) + } + + /// Python's `_polyglot_select_output_type_slots`. + fn type_slots(&self, select: Option<&Expression>, relations: &Relations) -> Fact> { + let select: Option<&Expression> = unwrap_annotations(select); + if let Some((left, right, by_name)) = select.and_then(set_operation) { + let left_slots: Vec = self.type_slots(Some(left), relations)?; + if left_slots.is_empty() { + return Ok(Vec::new()); + } + let right_slots: Vec = self.type_slots(Some(right), relations)?; + if right_slots.is_empty() { + return Ok(Vec::new()); + } + return self.combined_slots(&left_slots, &right_slots, by_name); + } + let Some(select) = select.filter(|select| kind(Some(select)) == SELECT_AST_KIND) else { + return Ok(Vec::new()); + }; + let inferred: Vec<(String, String)> = self.direct_select_types(Some(select), relations)?; + let mut slots: Vec = Vec::new(); + for projection in select.get_expressions() { + let projection: Option<&Expression> = unwrap_annotations(Some(projection)); + let output: &str = output_name(projection); + if is_star(projection) || output.is_empty() || output == WILDCARD { + return Ok(Vec::new()); + } + let mut inferred_type: Option = ci_get(&inferred, output).cloned(); + if inferred_type.is_none() && kind(projected_expression(projection)) == NULL_AST_KIND { + inferred_type = Some(NULL_SET_OPERATION_TYPE.to_owned()); + } + slots.push((output.to_owned(), inferred_type)); + } + Ok(slots) + } + + fn combined_slots(&self, left: &[Slot], right: &[Slot], by_name: bool) -> Fact> { + if by_name { + let mut right_types: Vec = Vec::new(); + for (name, slot_type) in right { + right_types = dict_set(right_types, name, slot_type.clone()); + } + let mut slots: Vec = Vec::with_capacity(left.len()); + for (name, left_type) in left { + let right_type: Option<&str> = ci_get_optional(&right_types, name); + slots.push(( + name.clone(), + self.common_type(left_type.as_deref(), right_type)?, + )); + } + return Ok(slots); + } + if left.len() != right.len() { + return Ok(Vec::new()); + } + let mut slots: Vec = Vec::with_capacity(left.len()); + for ((name, left_type), (_, right_type)) in left.iter().zip(right) { + slots.push(( + name.clone(), + self.common_type(left_type.as_deref(), right_type.as_deref())?, + )); + } + Ok(slots) + } + + /// Python's `_polyglot_common_set_operation_type`. + fn common_type(&self, left: Option<&str>, right: Option<&str>) -> Fact> { + let null: Option<&str> = Some(NULL_SET_OPERATION_TYPE); + if left == null && right == null { + return Ok(None); + } + if left == null { + return Ok(right.map(str::to_owned)); + } + if right == null { + return Ok(left.map(str::to_owned)); + } + let (Some(left), Some(right)) = (left, right) else { + return Ok(None); + }; + Ok(self.types_equal(left, right)?.then(|| left.to_owned())) + } + + /// Python's `_polyglot_types_equal`. + fn types_equal(&self, left: &str, right: &str) -> Fact { + Ok(left == right || self.normalized(left)? == self.normalized(right)?) + } + + /// Python's `normalize_type`, or a deferral where the native normalization defers. + fn normalized(&self, type_sql: &str) -> Fact { + normalize_type(type_sql, self.profile.dialect) + .map(|normalization| normalization.normalized) + .ok_or_else(|| format!("type normalization of {type_sql} defers")) + } + + /// Python's `_polyglot_direct_select_output_types`. + fn direct_select_types( + &self, + select: Option<&Expression>, + relations: &Relations, + ) -> Fact> { + let Some(select) = select.filter(|select| kind(Some(select)) == SELECT_AST_KIND) else { + return Ok(Vec::new()); + }; + let mut by_alias: Relations = Vec::new(); + for table in direct_tables(select) { + let table_name: &str = table.get_name(); + let Some(column_types) = ci_get(relations, table_name) else { + continue; + }; + let column_types: Shape = Rc::clone(column_types); + by_alias = dict_set(by_alias, table_name, Rc::clone(&column_types)); + let alias: &str = alias_or_name(table); + if !alias.is_empty() { + by_alias = dict_set(by_alias, alias, column_types); + } + } + let mut inferred: Vec<(String, String)> = Vec::new(); + for projection in select.get_expressions() { + let projection: Option<&Expression> = unwrap_annotations(Some(projection)); + if let Some(star) = projection.filter(|projection| is_star(Some(projection))) { + for (column, column_type) in star_types(star, &by_alias)? { + inferred = dict_set(inferred, &column, column_type); + } + continue; + } + let output: &str = output_name(projection); + if output.is_empty() || output == WILDCARD { + continue; + } + let expression: Option<&Expression> = projected_expression(projection); + if let Some(inferred_type) = self.expression_type_in(expression, &by_alias)? { + inferred = dict_set(inferred, output, inferred_type); + } + } + Ok(inferred) + } + + /// Python's `_polyglot_direct_expression_type`. + fn expression_type_in( + &self, + expression: Option<&Expression>, + by_alias: &Relations, + ) -> Fact> { + let expression: Option<&Expression> = unwrap_annotations(expression); + let node_kind: &str = kind(expression); + if let Some(inferred) = self.expression_type(expression)? { + return Ok(Some(inferred)); + } + let Some(node) = expression else { + return Ok(None); + }; + if node_kind == COLUMN_AST_KIND { + return direct_column_type(node, by_alias); + } + if BOOLEAN_RESULT_AST_KINDS.contains(&node_kind) { + return Ok(Some(BOOLEAN_TYPE.to_owned())); + } + if node_kind == CONCAT_AST_KIND { + return self.concat_type(node, by_alias); + } + if node_kind == SUBSTRING_AST_KIND { + return self.value_type(arg(Some(node), "this")?, by_alias); + } + if TYPE_PASSTHROUGH_AST_KINDS.contains(&node_kind) { + if let Some(inner) = node.get_this() { + return self.expression_type_in(Some(inner), by_alias); + } + return self.value_type(arg(Some(node), "this")?, by_alias); + } + let results: Vec> = result_expressions(node)?; + if results.is_empty() { + return Ok(None); + } + self.common_result_type(&results, by_alias) + } + + /// The type of a converted payload value; a non-expression has none. + fn value_type(&self, value: Option, by_alias: &Relations) -> Fact> { + match value { + Some(PyValue::Expr(inner)) => self.expression_type_in(Some(&inner), by_alias), + _ => Ok(None), + } + } + + fn concat_type(&self, node: &Expression, by_alias: &Relations) -> Fact> { + let operands: Vec = [arg(Some(node), "left")?, arg(Some(node), "right")?] + .into_iter() + .flatten() + .collect(); + if operands.len() != BINARY_OPERAND_COUNT { + return Ok(None); + } + let mut operand_types: Vec = Vec::with_capacity(BINARY_OPERAND_COUNT); + for operand in operands { + let PyValue::Expr(operand) = operand else { + return Ok(None); + }; + if string_literal(&operand)? { + operand_types.push(TEXT_TYPE.to_owned()); + continue; + } + let Some(operand_type) = self.expression_type_in(Some(&operand), by_alias)? else { + return Ok(None); + }; + operand_types.push(operand_type); + } + for operand_type in &operand_types { + if self.normalized(operand_type)?.family != TypeFamily::String { + return Ok(None); + } + } + Ok(Some(TEXT_TYPE.to_owned())) + } + + /// Python's `_polyglot_common_result_type`. + fn common_result_type( + &self, + expressions: &[Option], + by_alias: &Relations, + ) -> Fact> { + let mut resolved: Vec = Vec::new(); + for expression in expressions { + let Some(expression) = expression else { + return Ok(None); + }; + let expression: Option<&Expression> = unwrap_annotations(Some(expression)); + if kind(expression) == NULL_AST_KIND { + continue; + } + let Some(resolved_type) = self.expression_type_in(expression, by_alias)? else { + return Ok(None); + }; + resolved.push(resolved_type); + } + let Some((first, others)) = resolved.split_first() else { + return Ok(None); + }; + for other in others { + if !self.types_equal(first, other)? { + return Ok(None); + } + } + Ok(Some(first.clone())) + } + + /// Python's `_polyglot_expression_type`. + fn expression_type(&self, expression: Option<&Expression>) -> Fact> { + let node_kind: &str = kind(expression); + let node_name: &str = name(expression); + let function_name: &str = if node_name.is_empty() { + node_kind + } else { + node_name + }; + if node_kind != COLUMN_AST_KIND + && let Some(declared) = self.function_return_type(function_name)? + { + return Ok(Some(declared)); + } + if BOOLEAN_RESULT_AST_KINDS.contains(&node_kind) { + return Ok(Some(BOOLEAN_TYPE.to_owned())); + } + let Some(node) = expression.filter(|_| CAST_AST_KINDS.contains(&node_kind)) else { + return Ok(None); + }; + let value: Value = to_dict(node)?; + let target: Option<&Map> = value + .get(node_kind) + .and_then(Value::as_object) + .and_then(|payload| payload.get("to")) + .and_then(Value::as_object); + Ok(target.and_then(cast_target_type)) + } + + /// Python's `ExpressionInferenceProfile.function_return_type`. + fn function_return_type(&self, function_name: &str) -> Fact> { + let upper: String = upper(function_name); + Ok(self + .profile + .function_return_types + .iter() + .find(|(declared, _)| *declared == upper) + .map(|(_, return_type)| return_type.clone())) + } + + /// Python's `_polyglot_cte_passthrough_nullability_from_parsed`. + fn passthrough_nullability( + &self, + root: &Expression, + facts: &NullRelations, + ) -> Fact> { + let ctes: Vec<(&str, bool, &Expression)> = top_level_ctes(root); + if ctes.is_empty() { + return Ok(Vec::new()); + } + let mut relations: NullRelations = referenced_facts(root, facts); + for (cte_name, has_column_aliases, body) in ctes { + if has_column_aliases { + continue; + } + let inferred: Vec<(String, &'static str)> = + self.direct_select_nullability(body, &relations)?; + if !inferred.is_empty() { + relations = dict_set(relations, cte_name, Rc::new(inferred)); + } + } + self.direct_select_nullability(root, &relations) + } + + /// Python's `_polyglot_direct_select_output_nullability`. + fn direct_select_nullability( + &self, + select: &Expression, + relations: &NullRelations, + ) -> Fact> { + if kind(Some(select)) != SELECT_AST_KIND { + return Ok(Vec::new()); + } + let mut scoped: NullRelations = Vec::new(); + for table in direct_tables(select) { + let table_name: &str = table.get_name(); + if let Some(facts) = ci_get(relations, table_name) { + scoped = dict_set(scoped, table_name, Rc::new(facts.as_ref().clone())); + } + } + let known: bool = scoped.iter().any(|(_, facts)| has_known_nullability(facts)); + let (aliases, scoped): (Vec<(String, &'static str)>, NullRelations) = if known { + alias_nullability(select, scoped)? + } else { + (Vec::new(), scoped) + }; + let filter: Option = filter_context(select, &scoped)?; + let mut inferred: Vec<(String, &'static str)> = Vec::new(); + for projection in select.get_expressions() { + let projection: Option<&Expression> = unwrap_annotations(Some(projection)); + if is_star(projection) { + continue; + } + let output: &str = output_name(projection); + if output.is_empty() || output == WILDCARD { + continue; + } + let expression: Option<&Expression> = projected_expression(projection); + let nullability: &'static str = if non_null_after_filter(expression, filter.as_ref())? { + NON_NULL_NULLABILITY + } else if known { + self.nullability(expression, &aliases, &scoped)? + } else { + self.shallow_nullability(expression)? + }; + if nullability != UNKNOWN_NULLABILITY { + inferred = dict_set(inferred, output, nullability); + } + } + Ok(inferred) + } + + /// Python's `_infer_polyglot_nullability`. + fn nullability( + &self, + expression: Option<&Expression>, + aliases: &[(String, &'static str)], + scoped: &NullRelations, + ) -> Fact<&'static str> { + let node_kind: &str = kind(expression); + match node_kind { + NULL_AST_KIND => return Ok(NULLABLE_NULLABILITY), + LITERAL_AST_KIND | COUNT_AST_KIND | IS_NULL_AST_KIND => { + return Ok(NON_NULL_NULLABILITY); + } + TRY_CAST_AST_KIND => return Ok(UNKNOWN_NULLABILITY), + _ => {} + } + if let Some(column) = expression.filter(|_| node_kind == COLUMN_AST_KIND) { + return column_nullability(column, aliases, scoped); + } + if node_kind == CAST_AST_KIND { + return match expression.and_then(Expression::get_this) { + Some(inner) => self.nullability(Some(inner), aliases, scoped), + None => Ok(UNKNOWN_NULLABILITY), + }; + } + let rule: Option<&str> = self.rule(node_kind)?; + if node_kind != COALESCE_AST_KIND && rule.is_none() { + return Ok(UNKNOWN_NULLABILITY); + } + let mut arguments: Vec<&'static str> = Vec::new(); + for child in expression_args(expression) { + arguments.push(self.nullability(Some(child), aliases, scoped)?); + } + Ok(combined(node_kind, rule, &arguments)) + } + + /// Python's `_infer_polyglot_shallow_nullability`. + fn shallow_nullability(&self, expression: Option<&Expression>) -> Fact<&'static str> { + let node_kind: &str = kind(expression); + match node_kind { + NULL_AST_KIND => return Ok(NULLABLE_NULLABILITY), + LITERAL_AST_KIND | COUNT_AST_KIND | IS_NULL_AST_KIND => { + return Ok(NON_NULL_NULLABILITY); + } + COLUMN_AST_KIND | TRY_CAST_AST_KIND => return Ok(UNKNOWN_NULLABILITY), + _ => {} + } + if node_kind == CAST_AST_KIND { + return match expression.and_then(Expression::get_this) { + Some(inner) => self.shallow_nullability(Some(inner)), + None => Ok(UNKNOWN_NULLABILITY), + }; + } + let rule: Option<&str> = self.rule(node_kind)?; + if node_kind != COALESCE_AST_KIND && rule.is_none() { + return Ok(UNKNOWN_NULLABILITY); + } + let mut arguments: Vec<&'static str> = Vec::new(); + for child in expression_args(expression) { + arguments.push(self.shallow_nullability(Some(child))?); + } + Ok(combined(node_kind, rule, &arguments)) + } + + /// `inference_profile.function_nullability_rule(kind)`. + fn rule(&self, node_kind: &str) -> Fact> { + let rules: &Pairs = self + .profile + .rules + .ok_or("an adapter nullability rule Python does not ship")?; + let upper: String = upper(node_kind); + Ok(rules + .iter() + .find(|(declared, _)| *declared == upper) + .map(|(_, rule)| rule.as_str())) + } +} + +/// One set operation output slot: its name and type, None where unproven. +type Slot = (String, Option); + +/// COALESCE's or an adapter rule's nullability over the argument nullabilities. +fn combined(node_kind: &str, rule: Option<&str>, arguments: &[&'static str]) -> &'static str { + if node_kind == COALESCE_AST_KIND { + if arguments.contains(&NON_NULL_NULLABILITY) { + return NON_NULL_NULLABILITY; + } + if !arguments.is_empty() && arguments.iter().all(|value| *value == NULLABLE_NULLABILITY) { + return NULLABLE_NULLABILITY; + } + return UNKNOWN_NULLABILITY; + } + match rule { + Some(FIRST_ARG_RULE) => arguments.first().copied().unwrap_or(UNKNOWN_NULLABILITY), + Some(CONDITIONAL_RESULT_RULE) => conditional_result(arguments), + _ => UNKNOWN_NULLABILITY, + } +} + +/// Python's `conditional_result_nullability`. +fn conditional_result(arguments: &[&'static str]) -> &'static str { + let [_, when_true, when_false, ..] = arguments else { + return UNKNOWN_NULLABILITY; + }; + if *when_true == NON_NULL_NULLABILITY && *when_false == NON_NULL_NULLABILITY { + return NON_NULL_NULLABILITY; + } + if *when_true == NULLABLE_NULLABILITY || *when_false == NULLABLE_NULLABILITY { + return NULLABLE_NULLABILITY; + } + UNKNOWN_NULLABILITY +} + +/// Python's `_infer_polyglot_column_nullability`. +fn column_nullability( + column: &Expression, + aliases: &[(String, &'static str)], + scoped: &NullRelations, +) -> Fact<&'static str> { + let column_name: &str = column.get_name(); + if column_name.is_empty() { + return Ok(UNKNOWN_NULLABILITY); + } + let table_name: String = column_table_name(column)?; + if !table_name.is_empty() { + if dict_get(aliases, &table_name) == Some(&NULLABLE_NULLABILITY) { + return Ok(NULLABLE_NULLABILITY); + } + return Ok(dict_get(scoped, &table_name) + .and_then(|facts| dict_get(facts, column_name)) + .copied() + .unwrap_or(UNKNOWN_NULLABILITY)); + } + let matches: Vec<&'static str> = scoped + .iter() + .filter_map(|(_, facts)| dict_get(facts, column_name).copied()) + .collect(); + Ok(match matches.as_slice() { + [only] => only, + _ => UNKNOWN_NULLABILITY, + }) +} + +/// Python's `_polyglot_alias_nullability_from_select`, copying facts to aliases in `scoped`. +fn alias_nullability( + select: &Expression, + mut scoped: NullRelations, +) -> Fact<(Vec<(String, &'static str)>, NullRelations)> { + let mut aliases: Vec<(String, &'static str)> = Vec::new(); + let mut current: Vec = Vec::new(); + let value: Value = to_dict(select)?; + let Some(payload) = value.get("select").and_then(Value::as_object) else { + return Ok((aliases, scoped)); + }; + let from: Option<&Vec> = payload + .get("from") + .and_then(Value::as_object) + .and_then(|from| from.get("expressions")) + .and_then(Value::as_array); + if let Some([relation]) = from.map(Vec::as_slice) + && let Some(table) = relation + .get(TABLE_AST_KIND) + .filter(|table| table.is_object()) + { + let (alias, table_name) = table_alias_and_name(table); + current.push(alias.clone()); + aliases = dict_set(aliases, &alias, UNKNOWN_NULLABILITY); + scoped = copy_facts_to_alias(&alias, &table_name, scoped); + } + let Some(joins) = payload.get("joins").and_then(Value::as_array) else { + return Ok((aliases, scoped)); + }; + for join in joins.iter().filter_map(Value::as_object) { + let Some(table) = join + .get("this") + .filter(|this| this.is_object()) + .and_then(|this| this.get(TABLE_AST_KIND)) + .filter(|table| table.is_object()) + else { + continue; + }; + let (joined, joined_name) = table_alias_and_name(table); + let side: String = match join.get("kind") { + None | Some(Value::Null) => String::new(), + Some(Value::String(side)) => upper(side), + Some(_) => return Err("a join side Python stringifies".to_owned()), + }; + let current_side: Option<&'static str> = match side.as_str() { + JOIN_RIGHT | JOIN_FULL => Some(NULLABLE_NULLABILITY), + _ => None, + }; + if let Some(nullability) = current_side { + for alias in ¤t { + aliases = dict_set(aliases, alias, nullability); + } + } + let joined_nullability: &'static str = match side.as_str() { + JOIN_LEFT | JOIN_FULL => NULLABLE_NULLABILITY, + _ => UNKNOWN_NULLABILITY, + }; + aliases = dict_set(aliases, &joined, joined_nullability); + current.push(joined.clone()); + scoped = copy_facts_to_alias(&joined, &joined_name, scoped); + } + Ok((aliases, scoped)) +} + +/// Python's `_polyglot_table_payload_alias_and_name`. +fn table_alias_and_name(table: &Value) -> (String, String) { + let table_name: String = raw_name_payload(table.get("name")); + let alias: String = raw_name_payload(table.get("alias")); + ( + if alias.is_empty() { + table_name.clone() + } else { + alias + }, + table_name, + ) +} + +/// Python's `_copy_table_facts_to_alias`. +fn copy_facts_to_alias(alias: &str, table_name: &str, mut scoped: NullRelations) -> NullRelations { + if alias == table_name || dict_get(&scoped, alias).is_some() { + return scoped; + } + if let Some(facts) = dict_get(&scoped, table_name).cloned() { + scoped.push((alias.to_owned(), facts)); + } + scoped +} + +fn has_known_nullability(facts: &[(String, &'static str)]) -> bool { + facts.iter().any(|(_, value)| *value != UNKNOWN_NULLABILITY) +} + +/// Python's `_polyglot_non_null_filter_context`. +fn filter_context(select: &Expression, nullability: &NullRelations) -> Fact> { + let Some(clause) = where_clause(select)? else { + return Ok(None); + }; + let Some(clause) = clause.as_object() else { + return Ok(None); + }; + let references: Vec<(String, String)> = non_null_conjuncts(clause.get("this")); + if references.is_empty() { + return Ok(None); + } + let mut relations: Vec<(String, NullShape)> = Vec::new(); + for table in direct_tables(select) { + let table_name: &str = table.get_name(); + let alias: &str = alias_or_name(table); + if let Some(columns) = ci_get(nullability, table_name) { + let key: &str = if alias.is_empty() { table_name } else { alias }; + relations.push((key.to_owned(), Rc::clone(columns))); + } + } + let columns: HashSet<(String, String)> = references + .iter() + .filter_map(|reference| resolved_column(reference, &relations)) + .collect(); + Ok((!columns.is_empty()).then_some((relations, columns))) +} + +/// Python's `_polyglot_non_null_conjuncts`. +fn non_null_conjuncts(payload: Option<&Value>) -> Vec<(String, String)> { + let Some(payload) = payload.and_then(Value::as_object) else { + return Vec::new(); + }; + if let Some(paren) = payload.get("paren").and_then(Value::as_object) { + return non_null_conjuncts(paren.get("this")); + } + if let Some(and) = payload.get("and").and_then(Value::as_object) { + let mut references: Vec<(String, String)> = non_null_conjuncts(and.get("left")); + references.extend(non_null_conjuncts(and.get("right"))); + return references; + } + let Some(is_null) = payload.get(IS_NULL_AST_KIND).and_then(Value::as_object) else { + return Vec::new(); + }; + if is_null.is_empty() || is_null.get("not") != Some(&Value::Bool(true)) { + return Vec::new(); + } + let Some(column) = is_null + .get("this") + .and_then(Value::as_object) + .and_then(|this| this.get(COLUMN_AST_KIND)) + .and_then(Value::as_object) + else { + return Vec::new(); + }; + let column_name: String = raw_name_payload(column.get("name")); + let table_name: String = raw_name_payload(column.get("table")); + if column_name.is_empty() { + return Vec::new(); + } + vec![(table_name, column_name)] +} + +/// Python's `_polyglot_resolved_relation_column`. +fn resolved_column( + reference: &(String, String), + relations: &[(String, NullShape)], +) -> Option<(String, String)> { + let (table_name, column_name) = reference; + let matching: Vec<(String, String)> = relations + .iter() + .filter(|(alias, _)| table_name.is_empty() || casefold(alias) == casefold(table_name)) + .filter_map(|(alias, columns)| folded_column(alias, columns, column_name)) + .collect(); + match <[(String, String); 1]>::try_from(matching) { + Ok([only]) => Some(only), + Err(_) => None, + } +} + +fn folded_column(alias: &str, columns: &NullShape, column_name: &str) -> Option<(String, String)> { + let key: &str = ci_key(columns, column_name)?; + Some((casefold(alias), casefold(key))) +} + +/// Python's `_polyglot_expression_is_non_null_after_filter`. +fn non_null_after_filter( + expression: Option<&Expression>, + context: Option<&FilterContext>, +) -> Fact { + let Some((relations, columns)) = context else { + return Ok(false); + }; + let Some(reference) = direct_column_reference(expression)? else { + return Ok(false); + }; + Ok(resolved_column(&reference, relations).is_some_and(|resolved| columns.contains(&resolved))) +} + +/// Python's `_polyglot_direct_column_reference`. +fn direct_column_reference(expression: Option<&Expression>) -> Fact> { + let mut expression: Option<&Expression> = unwrap_annotations(expression); + if kind(expression) == CAST_AST_KIND { + expression = unwrap_annotations(expression.and_then(Expression::get_this)); + } + if kind(expression) != COLUMN_AST_KIND { + return Ok(None); + } + let column_name: &str = name(expression); + if column_name.is_empty() { + return Ok(None); + } + let table_name: String = name_payload(arg(expression, "table")?.as_ref()); + Ok(Some((table_name, column_name.to_owned()))) +} + +/// Python's `_polyglot_filtered_non_null_outputs` once its filter test passed. +fn filtered_non_null(root: &Expression, nullability: &NullRelations) -> Fact> { + let select: Option<&Expression> = if kind(Some(root)) == SELECT_AST_KIND { + Some(root) + } else { + root.dfs() + .skip(1) + .find(|node| node.variant_name() == SELECT_AST_KIND) + }; + let Some(select) = select else { + return Ok(HashSet::new()); + }; + let context: Option = filter_context(select, nullability)?; + let mut outputs: HashSet = HashSet::new(); + for projection in select.get_expressions() { + let projection: Option<&Expression> = unwrap_annotations(Some(projection)); + let output: &str = output_name(projection); + if output.is_empty() || output == WILDCARD { + continue; + } + if non_null_after_filter(projected_expression(projection), context.as_ref())? { + outputs.insert(output.to_owned()); + } + } + Ok(outputs) +} + +/// Python's `_polyglot_referenced_relation_facts`. +fn referenced_facts(root: &Expression, facts: &[(String, V)]) -> Vec<(String, V)> { + let mut referenced: Vec<(String, V)> = Vec::new(); + for table in find_all(root, TABLE_AST_KIND) { + let table_name: &str = table.get_name(); + if let Some(column_facts) = dict_get(facts, table_name) { + referenced = dict_set(referenced, table_name, column_facts.clone()); + } + } + referenced +} + +/// Python's `_polyglot_direct_column_type`. +fn direct_column_type(column: &Expression, by_alias: &Relations) -> Fact> { + let column_name: &str = column.get_name(); + let table_name: String = column_table_name(column)?; + if !table_name.is_empty() { + return Ok(ci_get(by_alias, &table_name) + .and_then(|column_types| ci_get(column_types, column_name)) + .cloned()); + } + let matching: Vec<&String> = distinct_shapes(by_alias) + .into_iter() + .filter_map(|column_types| ci_get(column_types, column_name)) + .collect(); + Ok(match matching.as_slice() { + [only] => Some((*only).clone()), + _ => None, + }) +} + +/// The relations of `by_alias` in order, each `Rc` once, as Python's `id()` dedup keeps them. +fn distinct_shapes(by_alias: &Relations) -> Vec<&Shape> { + let mut distinct: Vec<&Shape> = Vec::new(); + for (_, shape) in by_alias { + if !distinct.iter().any(|seen| Rc::ptr_eq(seen, shape)) { + distinct.push(shape); + } + } + distinct +} + +/// Python's `_polyglot_star_output_types`. +fn star_types(star: &Expression, by_alias: &Relations) -> Fact> { + if py_truthy(arg(Some(star), "rename")?.as_ref()) { + return Ok(Vec::new()); + } + let table_name: String = name_payload(arg(Some(star), "table")?.as_ref()); + let sources: Vec<&Shape> = if table_name.is_empty() { + distinct_shapes(by_alias) + } else { + ci_get(by_alias, &table_name).into_iter().collect() + }; + let excluded: HashSet = listed_names(arg(Some(star), "except")?, false)?; + let replaced: HashSet = listed_names(arg(Some(star), "replace")?, true)?; + let mut inferred: Vec<(String, String)> = Vec::new(); + let mut ambiguous: Vec = Vec::new(); + for column_types in sources { + for (column_name, column_type) in column_types.iter() { + let folded: String = casefold(column_name); + if excluded.contains(&folded) || replaced.contains(&folded) { + continue; + } + if let Some((existing, _)) = inferred.iter().find(|(name, _)| casefold(name) == folded) + { + ambiguous.push(existing.clone()); + continue; + } + inferred.push((column_name.clone(), column_type.clone())); + } + } + inferred.retain(|(name, _)| !ambiguous.contains(name)); + Ok(inferred) +} + +/// The folded names of a star's `except` list, or of its `replace` aliases. +fn listed_names(value: Option, aliases: bool) -> Fact> { + let items: Vec = match value { + None => Vec::new(), + Some(PyValue::Exprs(_)) => return Ok(HashSet::new()), + Some(PyValue::Raw(Value::Array(items))) => items, + Some(PyValue::Raw(raw)) if !py_truthy(Some(&PyValue::Raw(raw.clone()))) => Vec::new(), + Some(_) => return Err("a star modifier Python iterates unusually".to_owned()), + }; + Ok(items + .iter() + .filter(|item| !aliases || item.is_object()) + .map(|item| match aliases { + true => raw_name_payload(item.get("alias")), + false => raw_name_payload(Some(item)), + }) + .filter(|name| !name.is_empty()) + .map(|name| casefold(&name)) + .collect()) +} + +/// Whether `node` is a literal whose `literal_type` arg is Python's `"string"`. +fn string_literal(node: &Expression) -> Fact { + if node.variant_name() != LITERAL_AST_KIND { + return Ok(false); + } + Ok(matches!( + arg(Some(node), "literal_type")?, + Some(PyValue::Raw(Value::String(literal_type))) if literal_type == STRING_LITERAL_TYPE + )) +} + +/// Python's `_polyglot_result_expressions`; None stands for a value that is not an expression. +fn result_expressions(node: &Expression) -> Fact>> { + let node_kind: &str = node.variant_name(); + if node_kind == COALESCE_AST_KIND { + return Ok(match arg(Some(node), "expressions")? { + Some(PyValue::Exprs(values)) => values.into_iter().map(Some).collect(), + Some(PyValue::Raw(Value::Array(values))) => values.iter().map(|_| None).collect(), + _ => Vec::new(), + }); + } + if node_kind == IF_FUNC_AST_KIND { + let mut values: Vec> = Vec::new(); + for key in ["true_value", "false_value"] { + if let Some(value) = arg(Some(node), key)? { + values.push(expression_value(value)); + } + } + return Ok(values); + } + if node_kind == CASE_AST_KIND { + return case_results(node); + } + if node_kind == FUNCTION_AST_KIND && upper(node.get_name()) == NULLIF_FUNCTION_NAME { + return Ok(match arg(Some(node), "args")? { + Some(PyValue::Exprs(mut values)) if !values.is_empty() => { + vec![Some(values.swap_remove(0))] + } + Some(PyValue::Raw(Value::Array(values))) if !values.is_empty() => vec![None], + _ => Vec::new(), + }); + } + + Ok(Vec::new()) +} + +fn expression_value(value: PyValue) -> Option { + match value { + PyValue::Expr(expression) => Some(expression), + _ => None, + } +} + +/// CASE's result branches by child position, as Python indexes `children()`. +fn case_results(node: &Expression) -> Fact>> { + let node_children: Vec<&Expression> = children(node); + let mut values: Vec> = Vec::new(); + let when_count: Option = match arg(Some(node), "whens")? { + Some(PyValue::Exprs(whens)) => Some(whens.len()), + Some(PyValue::Raw(Value::Array(whens))) => Some(whens.len()), + _ => None, + }; + if let Some(when_count) = when_count { + let first: usize = usize::from(arg(Some(node), "operand")?.is_some()); + for index in 0..when_count { + let child: &Expression = node_children + .get(first + index * 2 + 1) + .ok_or("Python indexes past CASE's children")?; + values.push(Some(child.clone())); + } + } + if arg(Some(node), "else_")?.is_some() + && let Some(last) = node_children.last() + { + values.push(Some((*last).clone())); + } + Ok(values) +} + +/// Python's cast-target rendering in `_polyglot_expression_type`. +fn cast_target_type(target: &Map) -> Option { + let raw_type: &str = target + .get("data_type") + .and_then(Value::as_str) + .filter(|raw| !raw.is_empty())?; + if upper(raw_type) == CUSTOM_TYPE_NAME + && let Some(custom) = target + .get("name") + .and_then(Value::as_str) + .filter(|custom| !custom.is_empty()) + { + return Some(upper(custom)); + } + let lower: String = casefold(raw_type); + if lower == TIMESTAMP_TYPE_NAME && target.get("timezone") == Some(&Value::Bool(true)) { + return Some(TIMESTAMP_TZ_TYPE.to_owned()); + } + let type_name: String = POLYGLOT_TYPE_NAMES + .iter() + .find(|(raw, _)| *raw == raw_type) + .map_or_else( + || upper(&raw_type.replace('_', " ")), + |(_, rendered)| (*rendered).to_owned(), + ); + if VARCHAR_DATA_TYPES.contains(&lower.as_str()) + && let Some(length) = python_int(target.get("length")) + { + return Some(format!("VARCHAR({length})")); + } + if type_name == DECIMAL_TYPE + && let Some(precision) = python_int(target.get("precision")) + { + return Some(match python_int(target.get("scale")) { + Some(scale) => format!("DECIMAL({precision}, {scale})"), + None => format!("DECIMAL({precision})"), + }); + } + Some(type_name) +} + +/// Python's `str.casefold`, exact for ASCII; non-ASCII text marks the recovery deferred. +fn casefold(text: &str) -> String { + flag_non_ascii(text); + text.to_ascii_lowercase() +} + +/// Python's `str.upper`, exact for ASCII; non-ASCII text marks the recovery deferred. +fn upper(text: &str) -> String { + flag_non_ascii(text); + text.to_ascii_uppercase() +} + +fn flag_non_ascii(text: &str) { + if !text.is_ascii() { + NON_ASCII_FOLDED.set(true); + } +} + +fn dict_get<'a, V>(dict: &'a [(String, V)], key: &str) -> Option<&'a V> { + dict.iter() + .find(|(candidate, _)| candidate == key) + .map(|(_, value)| value) +} + +/// Python's `dict[key] = value`: replace in place, otherwise append. +fn dict_set(mut dict: Vec<(String, V)>, key: &str, value: V) -> Vec<(String, V)> { + match dict.iter_mut().find(|(candidate, _)| candidate == key) { + Some((_, existing)) => *existing = value, + None => dict.push((key.to_owned(), value)), + } + dict +} + +/// Python's `_case_insensitive_mapping_get` over values that are never None. +fn ci_get<'a, V>(dict: &'a [(String, V)], key: &str) -> Option<&'a V> { + if let Some(direct) = dict_get(dict, key) { + return Some(direct); + } + unique_folded(dict, key) +} + +/// Python's `_case_insensitive_mapping_get` over values that may be None. +fn ci_get_optional<'a>(dict: &'a [(String, Option)], key: &str) -> Option<&'a str> { + if let Some(Some(direct)) = dict_get(dict, key) { + return Some(direct); + } + unique_folded(dict, key).and_then(Option::as_deref) +} + +fn unique_folded<'a, V>(dict: &'a [(String, V)], key: &str) -> Option<&'a V> { + let folded: String = casefold(key); + let matches: Vec<&V> = dict + .iter() + .filter(|(candidate, _)| casefold(candidate) == folded) + .map(|(_, value)| value) + .collect(); + match matches.as_slice() { + [only] => Some(only), + _ => None, + } +} + +/// Python's `_case_insensitive_mapping_key`. +fn ci_key<'a, V>(dict: &'a [(String, V)], key: &str) -> Option<&'a str> { + if let Some((candidate, _)) = dict.iter().find(|(candidate, _)| candidate == key) { + return Some(candidate); + } + let folded: String = casefold(key); + let matches: Vec<&str> = dict + .iter() + .filter(|(candidate, _)| casefold(candidate) == folded) + .map(|(candidate, _)| candidate.as_str()) + .collect(); + match matches.as_slice() { + [only] => Some(only), + _ => None, + } +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dict_walk.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dict_walk.rs index d11f30c0ae..96b1a60d02 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dict_walk.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dict_walk.rs @@ -1,10 +1,14 @@ -//! Python's dict walk over a parsed query's `to_dict()` payload, on the same serde values. +//! Python's view of a parsed query: the wheel's expression accessors and its dict walk. -use serde_json::{Map, Value}; +use polyglot_sql::expressions::Cte; +use polyglot_sql::traversal::ExpressionWalk; +use polyglot_sql::{ComplexityGuardOptions, Dialect, Expression, ParseOptions, ast_json}; +use serde_json::{Map, Value, json}; use crate::assembly::analysis_session::constants::{ - COLUMN_AST_KIND, DEPENDENCY_FUNCTION_NAMES, FUNCTION_AST_KIND, RENDERED_TYPE_NAMES, - STAR_AST_KIND, TABLE_AST_KIND, + ALIAS_AST_KIND, ANNOTATED_AST_KIND, COLUMN_AST_KIND, DEPENDENCY_FUNCTION_NAMES, + FUNCTION_AST_KIND, MAX_FUNCTION_CALL_DEPTH, RENDERED_TYPE_NAMES, STAR_AST_KIND, TABLE_AST_KIND, + WILDCARD, }; /// Python's `bool(value)`. @@ -142,7 +146,7 @@ pub(crate) fn render_type(node: Option<&Value>) -> Option { } /// Python's `str(value)` for a value `isinstance(value, int)` accepts. -fn python_int(value: Option<&Value>) -> Option { +pub(crate) fn python_int(value: Option<&Value>) -> Option { match value? { Value::Bool(flag) => Some(if *flag { "True" } else { "False" }.to_owned()), Value::Number(number) if number.is_i64() || number.is_u64() => Some(number.to_string()), @@ -154,3 +158,236 @@ fn python_int(value: Option<&Value>) -> Option { pub(crate) fn casefold(text: &str) -> String { text.to_ascii_lowercase() } + +/// A value the wheel hands Python for one payload key: an expression, a list of them, or data. +#[derive(Debug, Clone)] +pub(crate) enum PyValue { + Expr(Expression), + Exprs(Vec), + Raw(Value), +} + +/// The wheel's guarded `parse_one`; Ok(None) is the `PolyglotError` Python catches. +pub(crate) fn parse_one(sql: &str, dialect: &str) -> Result, String> { + let guard: ComplexityGuardOptions = + serde_json::from_value(json!({"maxFunctionCallDepth": MAX_FUNCTION_CALL_DEPTH})) + .map_err(|error| error.to_string())?; + let options: ParseOptions = ParseOptions { + complexity_guard: Some(guard), + }; + let parsed: Result, _> = Dialect::get_by_name(dialect) + .ok_or_else(|| format!("unknown dialect {dialect}"))? + .parse_with_options(sql, &options); + let mut expressions: Vec = match parsed { + Ok(expressions) => expressions, + Err(_) => return Ok(None), + }; + if expressions.len() != 1 { + return Ok(None); + } + Ok(expressions.pop()) +} + +/// `str(getattr(node, "kind", ""))`. +pub(crate) fn kind(node: Option<&Expression>) -> &'static str { + node.map_or("", Expression::variant_name) +} + +/// `node.name`, "" for None. +pub(crate) fn name(node: Option<&Expression>) -> &str { + node.map_or("", Expression::get_name) +} + +/// `node.output_name`, "" for None. +pub(crate) fn output_name(node: Option<&Expression>) -> &str { + node.map_or("", Expression::get_output_name) +} + +/// `node.alias_or_name`. +pub(crate) fn alias_or_name(node: &Expression) -> &str { + let alias: &str = node.get_alias(); + if alias.is_empty() { + node.get_name() + } else { + alias + } +} + +/// `node.is_star`. +pub(crate) fn is_star(node: Option<&Expression>) -> bool { + match node { + Some(Expression::Star(_)) => true, + Some(Expression::Column(column)) => column.name.name == WILDCARD, + _ => false, + } +} + +/// Python's `_unwrap_polyglot_annotations`. +pub(crate) fn unwrap_annotations(mut node: Option<&Expression>) -> Option<&Expression> { + while kind(node) == ANNOTATED_AST_KIND { + node = node.and_then(Expression::get_this); + } + node +} + +/// A projection's expression: an alias's `this`, otherwise the projection. +pub(crate) fn projected_expression(projection: Option<&Expression>) -> Option<&Expression> { + if kind(projection) == ALIAS_AST_KIND { + return projection.and_then(Expression::get_this); + } + projection +} + +/// `node.this` then `node.expressions`: Python's `_polyglot_expression_args`. +pub(crate) fn expression_args(node: Option<&Expression>) -> Vec<&Expression> { + let Some(node) = node else { + return Vec::new(); + }; + node.get_this() + .into_iter() + .chain(node.get_expressions()) + .collect() +} + +/// `node.children()`. +pub(crate) fn children(node: &Expression) -> Vec<&Expression> { + ExpressionWalk::children(node) +} + +/// Python's `_polyglot_direct_select_tables`: the table children. +pub(crate) fn direct_tables(node: &Expression) -> Vec<&Expression> { + children(node) + .into_iter() + .filter(|child| child.variant_name() == TABLE_AST_KIND) + .collect() +} + +/// `node.find_all(kind)`: descendants in depth-first order, the node itself excluded. +pub(crate) fn find_all<'a>(node: &'a Expression, wanted: &str) -> Vec<&'a Expression> { + node.dfs() + .skip(1) + .filter(|descendant| descendant.variant_name() == wanted) + .collect() +} + +/// `node.to_dict()`. +pub(crate) fn to_dict(node: &Expression) -> Result { + serde_json::to_value(node).map_err(|error| error.to_string()) +} + +/// The wheel's `expression_payload`: the tagged value's fields. +pub(crate) fn expression_payload(node: &Expression) -> Result, String> { + Ok(match to_dict(node)? { + Value::Object(map) => match map.into_iter().next() { + Some((_, Value::Object(payload))) => payload, + _ => Map::new(), + }, + _ => Map::new(), + }) +} + +/// `node.args.get(key)` (and `node.arg(key)` outside its special keys); None for Python's None. +pub(crate) fn arg(node: Option<&Expression>, key: &str) -> Result, String> { + let Some(node) = node else { + return Ok(None); + }; + Ok(expression_payload(node)?.remove(key).and_then(py_value)) +} + +/// The wheel's `value_to_python_object`; None where Python sees None. +fn py_value(value: Value) -> Option { + if let Ok(expression) = ast_json::expression_from_value(value.clone()) { + return Some(PyValue::Expr(expression)); + } + if let Ok(expressions) = ast_json::expressions_from_value(value.clone()) { + return Some(PyValue::Exprs(expressions)); + } + (!value.is_null()).then_some(PyValue::Raw(value)) +} + +/// Python's `bool()` of a converted value: expressions are always truthy. +pub(crate) fn py_truthy(value: Option<&PyValue>) -> bool { + match value { + None => false, + Some(PyValue::Expr(_)) => true, + Some(PyValue::Exprs(items)) => !items.is_empty(), + Some(PyValue::Raw(raw)) => truthy(Some(raw)), + } +} + +/// Python's `_polyglot_name_payload_value` of a converted value. +pub(crate) fn name_payload(value: Option<&PyValue>) -> String { + match value { + Some(PyValue::Raw(raw)) => raw_name_payload(Some(raw)), + _ => String::new(), + } +} + +/// Python's `_polyglot_name_payload_value` of plain data. +pub(crate) fn raw_name_payload(value: Option<&Value>) -> String { + match value { + Some(Value::String(text)) => text.clone(), + Some(Value::Object(object)) => object + .get("name") + .and_then(Value::as_str) + .unwrap_or_default() + .to_owned(), + _ => String::new(), + } +} + +/// Python's `_polyglot_column_table_name`: `to_dict()["column"]["table"]["name"]`. +pub(crate) fn column_table_name(node: &Expression) -> Result { + let value: Value = to_dict(node)?; + let table: Option<&Value> = value + .get("column") + .filter(|column| column.is_object()) + .and_then(|column| column.get("table")) + .filter(|table| table.is_object()); + Ok(raw_name_payload(table)) +} + +/// The top-level CTEs `with_ctes()` returns: name, whether it has column aliases, and its body. +pub(crate) fn top_level_ctes(node: &Expression) -> Vec<(&str, bool, &Expression)> { + let with = match node { + Expression::Select(select) => select.with.as_ref(), + Expression::Union(union) => union.with.as_ref(), + Expression::Intersect(intersect) => intersect.with.as_ref(), + Expression::Except(except) => except.with.as_ref(), + _ => None, + }; + with.map(|with| with.ctes.iter().map(cte_entry).collect()) + .unwrap_or_default() +} + +fn cte_entry(cte: &Cte) -> (&str, bool, &Expression) { + (cte.alias.name.as_str(), !cte.columns.is_empty(), &cte.this) +} + +/// A set operation's `arg("left")`, `arg("right")` and `arg("by_name")`. +pub(crate) fn set_operation(node: &Expression) -> Option<(&Expression, &Expression, bool)> { + match node { + Expression::Union(operation) => { + Some((&operation.left, &operation.right, operation.by_name)) + } + Expression::Intersect(operation) => { + Some((&operation.left, &operation.right, operation.by_name)) + } + Expression::Except(operation) => { + Some((&operation.left, &operation.right, operation.by_name)) + } + _ => None, + } +} + +/// A select's `arg("where_clause")` as plain data. +pub(crate) fn where_clause(node: &Expression) -> Result, String> { + let Expression::Select(select) = node else { + return Ok(None); + }; + select + .where_clause + .as_ref() + .map(|clause| serde_json::to_value(clause).map_err(|error| error.to_string())) + .transpose() +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dynamic_pivot.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dynamic_pivot.rs index 78f0b3bdba..fe152f03ee 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dynamic_pivot.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/dynamic_pivot.rs @@ -1,23 +1,25 @@ //! Python's `analyze_dynamic_column_contract` over the crate's parse of the model SQL. use std::collections::{HashMap, HashSet}; +use std::panic::{AssertUnwindSafe, catch_unwind}; -use polyglot_sql::{ComplexityGuardOptions, Dialect, Expression, ParseOptions}; -use serde_json::{Map, Value, json}; +use rayon::ThreadPool; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use serde_json::{Map, Value}; use sqlbuild_core::panics::main::catch_compiler_panic::catch_compiler_panic; use crate::assembly::analysis_session::_helpers::dict_walk::{ casefold, column_name, dict_list, identifier_name, is_single_wildcard, nested, node_key, - payload, relation_name, render_type, truthy, + parse_one, payload, relation_name, render_type, to_dict, truthy, }; use crate::assembly::analysis_session::constants::{ ALIAS_AST_KIND, CAST_AST_KIND, CTE_AST_KIND, DUCKDB_DIALECT, DYNAMIC_VALUE_SOURCE_KINDS, - MAX_FUNCTION_CALL_DEPTH, MOTHERDUCK_DIALECT, PIVOT_AST_KIND, QUERY_AST_KINDS, SELECT_AST_KIND, + MOTHERDUCK_DIALECT, PIVOT_AST_KIND, QUERY_AST_KINDS, SELECT_AST_KIND, SIMPLIFIED_PIVOT_DIALECTS, SUPPORTED_PIVOT_DIALECTS, TYPE_PRESERVING_AGGREGATES, UNKNOWN_NULLABILITY, UNKNOWN_TYPE, }; use crate::assembly::analysis_session::models::{ - ColumnFact, ContractProof, DynamicFamily, PivotOutcome, + ColumnFact, ContractProof, DynamicFamily, PivotModel, PivotOutcome, PivotTables, }; use crate::assembly::analysis_session::types::{Pairs, Shapes}; @@ -33,6 +35,47 @@ pub(crate) struct PivotFacts<'a> { pub(crate) families_by_table: &'a [(String, Vec)], } +/// Each model's proof in order; a model whose proof panics is deferred to Python. +pub(crate) fn pivot_outcomes(models: &[PivotModel], tables: &PivotTables) -> Vec { + let facts = pivot_facts(tables); + models + .iter() + .map(|model| guarded_outcome(model, &facts)) + .collect() +} + +/// Each model's proof in order on `pool`; a model whose proof panics is deferred to Python. +pub(crate) fn pooled_pivot_outcomes( + pool: &ThreadPool, + models: &[PivotModel], + tables: &PivotTables, +) -> Vec { + let facts = pivot_facts(tables); + pool.install(|| { + models + .par_iter() + .map(|model| guarded_outcome(model, &facts)) + .collect() + }) +} + +fn pivot_facts(tables: &PivotTables) -> PivotFacts<'_> { + PivotFacts { + dialect: &tables.dialect, + column_types: &tables.column_types, + authoritative_types: &tables.authoritative_types, + column_nullability: &tables.column_nullability, + families_by_table: &tables.families_by_table, + } +} + +fn guarded_outcome(model: &PivotModel, facts: &PivotFacts<'_>) -> PivotOutcome { + catch_unwind(AssertUnwindSafe(|| { + pivot_outcome(&model.sql, &model.families, facts) + })) + .unwrap_or(PivotOutcome::Deferred) +} + /// One CTE body by folded name; None for a CTE with column aliases. type CteMap<'a> = HashMap>; @@ -80,25 +123,9 @@ pub(crate) fn pivot_outcome( /// Python's `parse_one(...).to_dict()`, or None where Python reports a parse error. fn parsed(sql: &str, dialect: &str) -> Result, String> { - let guard: ComplexityGuardOptions = - serde_json::from_value(json!({"maxFunctionCallDepth": MAX_FUNCTION_CALL_DEPTH})) - .map_err(|error| error.to_string())?; - let options: ParseOptions = ParseOptions { - complexity_guard: Some(guard), - }; - let parsed: Result, _> = Dialect::get_by_name(dialect) - .ok_or_else(|| format!("unknown dialect {dialect}"))? - .parse_with_options(sql, &options); - let expressions: Vec = match parsed { - Ok(expressions) => expressions, - Err(_) => return Ok(None), - }; - let [expression] = expressions.as_slice() else { - return Ok(None); - }; - serde_json::to_value(expression) - .map(Some) - .map_err(|error| error.to_string()) + parse_one(sql, dialect)? + .map(|expression| to_dict(&expression)) + .transpose() } /// Casefolding equals Python's only for ASCII text. diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/enrichment.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/enrichment.rs index 2e176ff81e..4a2da05dde 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/enrichment.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/enrichment.rs @@ -6,11 +6,14 @@ use polyglot_sql::{AnalyzeQueryOptions, analyze_query}; use serde_json::{Map, Value, json}; use sqlbuild_core::panics::main::catch_compiler_panic::catch_compiler_panic; +use crate::assembly::analysis_session::_helpers::cte_facts::{ + Recovery, RecoveryInput, RecoveryProfile, recovery, +}; use crate::assembly::analysis_session::_helpers::dict_walk::truthy; use crate::assembly::analysis_session::constants::{ CAST_TRANSFORM, CONFIDENCE_HIGH, CONFIDENCE_MEDIUM, CONFIDENCE_UNKNOWN, FILTER_CONTEXT, - MAX_FUNCTION_CALL_DEPTH, NULL_KEYWORD, RESOLVED_SOURCE_CONFIDENCE, SELECT_SHAPE, - SET_OPERATION_SHAPE, TRANSFORM_AGGREGATION, TRANSFORM_CAST, TRANSFORM_CONSTANT, + MAX_FUNCTION_CALL_DEPTH, NON_NULL_NULLABILITY, NULL_KEYWORD, RESOLVED_SOURCE_CONFIDENCE, + SELECT_SHAPE, SET_OPERATION_SHAPE, TRANSFORM_AGGREGATION, TRANSFORM_CAST, TRANSFORM_CONSTANT, TRANSFORM_DIRECT, TRANSFORM_EXPRESSION, TRANSFORM_STAR, UNKNOWN_NULLABILITY, UNKNOWN_TYPE, WILDCARD, }; @@ -25,6 +28,8 @@ pub(crate) struct EnrichmentInput<'a> { pub(crate) input_schemas: &'a Shapes, pub(crate) dialect: &'a str, pub(crate) function_return_types: &'a Pairs, + /// Adapter nullability rules by function name; None where one is not a rule Python ships. + pub(crate) nullability_rules: Option<&'a Pairs>, } /// Python's successful re-analysis: columns, plain lineage facts and the star flag. @@ -75,7 +80,7 @@ fn analysed(input: &EnrichmentInput<'_>) -> Result, String> { Err(_) => return Ok(None), }; let analysis: Value = serde_json::to_value(analysis).map_err(|error| error.to_string())?; - Ok(projected(input, &analysis)) + Ok(projected(input, &analysis, &cleaned)) } /// Python's `_compact_analysis_schema` over the input shapes, nullability unknown. @@ -109,15 +114,26 @@ fn analysis_schema(input: &EnrichmentInput<'_>) -> Option { } /// Python's projection of `analyze_query` facts into columns and lineage. -fn projected(input: &EnrichmentInput<'_>, analysis: &Value) -> Option { +fn projected(input: &EnrichmentInput<'_>, analysis: &Value, cleaned: &str) -> Option { let projections: &Vec = analysis.get("projections")?.as_array()?; let shape: Option<&str> = analysis.get("shape").and_then(Value::as_str); if !matches!(shape, Some(SELECT_SHAPE | SET_OPERATION_SHAPE)) || !eligible(projections) { return None; } - if has_null_filter(analysis) || recovers_cte_facts(input, analysis) { - return None; - } + let recovery: Recovery = match recovery(&RecoveryInput { + cleaned_sql: cleaned, + input_schemas: input.input_schemas, + recover: recovers_cte_facts(input, analysis), + null_filter: has_null_filter(analysis), + profile: RecoveryProfile { + dialect: input.dialect, + function_return_types: input.function_return_types, + rules: input.nullability_rules, + }, + }) { + Ok(recovery) => recovery, + Err(_deferred) => return None, + }; let resources: HashMap<&str, (&str, &str)> = input .model .lineage_references @@ -136,10 +152,24 @@ fn projected(input: &EnrichmentInput<'_>, analysis: &Value) -> Option = if direct { + recovered(&recovery.types, name).cloned() + } else { + projection_type(projection, input.function_return_types)? + }; + let nullability: &str = if recovery.non_null_outputs.contains(name) { + NON_NULL_NULLABILITY + } else { + recovered(&recovery.nullability, name) + .filter(|_| direct) + .copied() + .unwrap_or_else(|| projection_nullability(projection, infer_nullability)) + }; columns.push(ColumnFact { name: name.to_owned(), - data_type: projection_type(projection, input.function_return_types)?, - nullability: projection_nullability(projection, infer_nullability).to_owned(), + data_type, + nullability: nullability.to_owned(), }); let (sources, confidence) = upstream(projection, &resources); let transform: u8 = transform_code(projection, !sources.is_empty()); @@ -176,7 +206,15 @@ fn projected(input: &EnrichmentInput<'_>, analysis: &Value) -> Option(facts: &'a [(String, V)], name: &str) -> Option<&'a V> { + facts + .iter() + .find(|(output, _)| output == name) + .map(|(_, value)| value) +} + +/// Whether Python's CTE pass-through recovery runs past its early return. fn recovers_cte_facts(input: &EnrichmentInput<'_>, analysis: &Value) -> bool { input.model.recover_cte_facts && truthy(analysis.get("cteFacts")) diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/mod.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/mod.rs index 1ff9c1dda6..3534a64196 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/mod.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod catalog_state; pub(crate) mod compact_batch; +pub(crate) mod cte_facts; pub(crate) mod dict_walk; pub(crate) mod dynamic_pivot; pub(crate) mod enrichment; diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/session.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/session.rs index cf945f7c71..90595240f6 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/session.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/session.rs @@ -1,7 +1,9 @@ //! The session's phases: Python's uncached model analysis, wave by wave. use std::collections::HashMap; +use std::sync::Arc; +use rayon::ThreadPool; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use crate::assembly::analysis_session::_helpers::catalog_state::SessionCatalog; @@ -21,8 +23,9 @@ use crate::assembly::analysis_session::constants::{ DEFERRAL_ANALYSIS, DEFERRAL_ENRICHMENT, UNKNOWN_NULLABILITY, UNKNOWN_TYPE, }; use crate::assembly::analysis_session::models::{ - AnalysisSession, Awaiting, ColumnFact, Deferral, DeferredAnalysis, LineageFacts, ModelAnalysis, - ModelOutcome, ModelRequest, Phase, PivotOutcome, SessionOutcome, SessionRequest, SessionStep, + AnalysisSession, Awaiting, ColumnFact, Deferral, DeferredAnalysis, FinishedSession, + LineageFacts, LineageRow, ModelAnalysis, ModelOutcome, ModelRequest, Phase, PivotOutcome, + PivotTables, SessionModelFacts, SessionOutcome, SessionRequest, SessionStep, }; use crate::assembly::analysis_session::types::{Pairs, Shapes}; use crate::semantic_validation::models::ProjectCatalog; @@ -148,23 +151,43 @@ impl AnalysisSession { } /// Every model's outcome and the binding catalog changes Python records. - pub(crate) fn finish(self) -> Result { + pub(crate) fn finish(self) -> Result<(SessionOutcome, FinishedSession), String> { if !matches!(self.phase, Phase::Done) { return Err("the session has not finished".to_owned()); } let dynamic_contracts: Vec = self.dynamic_contracts()?; + let pool: Result, String> = self.catalog.native.analysis_pool(); let models: Vec = self .outcomes .into_iter() .collect::>() .ok_or("the session left a model unanalysed")?; let (schema_additions, analysis_names) = self.catalog.into_changes(); - Ok(SessionOutcome { + let request: SessionRequest = self.request; + let mut model_facts: HashMap = HashMap::new(); + for (model, outcome) in request.models.iter().zip(&models) { + if let Some(facts) = session_model_facts(&outcome.analysis) { + model_facts.insert(model.name.clone(), facts); + } + } + let finished = FinishedSession { + tables: PivotTables { + dialect: request.dialect, + column_types: request.column_types, + authoritative_types: request.complete_schemas, + column_nullability: request.column_nullability, + families_by_table: request.dynamic_families_by_table, + }, + pool, + models: model_facts, + }; + let outcome = SessionOutcome { models, schema_additions, analysis_names, dynamic_contracts, - }) + }; + Ok((outcome, finished)) } /// Python's dynamic pivot proof of each model over the relation facts before analysis. @@ -352,6 +375,7 @@ impl AnalysisSession { input_schemas, dialect: &self.request.dialect, function_return_types: &self.request.function_return_types, + nullability_rules: self.request.nullability_rules.as_ref(), }) .collect(); let pool = self.catalog.native.analysis_pool()?; @@ -595,3 +619,28 @@ fn native_answer(model: usize, columns: Vec, has_star: bool) -> Defe binding_validated: false, } } + +/// A compiled model's output names and lineage from a successful analysis with native lineage. +fn session_model_facts(analysis: &ModelAnalysis) -> Option { + let rows: &Vec = match &analysis.lineage { + LineageFacts::Native(rows) | LineageFacts::NativeEnrichment(rows) => rows, + LineageFacts::PythonAnalysis | LineageFacts::PythonEnrichment => return None, + }; + analysis.analysis_succeeded.then(|| SessionModelFacts { + columns: analysis.columns.as_deref().map(column_names), + lineage: rows.iter().map(output_sources).collect(), + }) +} + +fn column_names(columns: &[ColumnFact]) -> Vec { + columns.iter().map(|column| column.name.clone()).collect() +} + +/// One lineage row as `(output column, [(resource name, column name)])`. +fn output_sources(row: &LineageRow) -> (String, Vec<(String, String)>) { + let mut sources: Vec<(String, String)> = Vec::with_capacity(row.sources.len()); + for (_, name, column) in &row.sources { + sources.push((name.clone(), column.clone())); + } + (row.output_column.clone(), sources) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/constants.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/constants.rs index d0d6fa5520..06f05d540a 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/constants.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/constants.rs @@ -95,3 +95,92 @@ pub(crate) const RENDERED_TYPE_NAMES: [(&str, &str); 12] = [ ]; /// The stack a standalone dynamic pivot proof parses on, as the analysis workers have. pub(crate) const PIVOT_WORKER_STACK_BYTES: usize = 16 * 1024 * 1024; +/// Python's `COMPACT_RELATION_STUB_PREFIX`: the relation name a shared query binds instead. +pub(crate) const RELATION_STUB_PREFIX: &str = "__sqlbuild_project_input_"; +/// Python's `COMPACT_REFERENCE_MARKER_PATTERN`: a reference call and the name it reads. +pub(crate) const REFERENCE_MARKER_PATTERN: &str = + r#"__(ref|seed|source|dbt_ref)\((?:"[^"]+"\s*,\s*)?"([^"]+)"\)"#; +/// Python's `COMPACT_UNSTUBBED_REFERENCE_KIND`, a reference kind sharing never stubs. +pub(crate) const UNSTUBBED_REFERENCE_KIND: &str = "dbt_ref"; +/// Python's `MIN_SHARED_BINDING_QUERY_MEMBERS`. +pub(crate) const MIN_SHARED_MEMBERS: usize = 2; +/// Text whose presence sends Python's qualifier search to its token scanner. +pub(crate) const QUALIFIED_SCAN_TOKENS: [&str; 5] = ["\"", "`", "[", "--", "/*"]; +/// Python's `str.isspace` over ASCII. +pub(crate) const PYTHON_ASCII_SPACES: &str = " \t\n\r\x0b\x0c\x1c\x1d\x1e\x1f"; +/// Stack for one standalone CTE fact recovery, whose AST walks recurse with query depth. +pub(crate) const CTE_FACT_WORKER_STACK_BYTES: usize = 16 * 1024 * 1024; +/// The wheel's node kinds Python's CTE fact recovery reads. +pub(crate) const ANNOTATED_AST_KIND: &str = "annotated"; +pub(crate) const LITERAL_AST_KIND: &str = "literal"; +pub(crate) const NULL_AST_KIND: &str = "null"; +pub(crate) const CONCAT_AST_KIND: &str = "concat"; +pub(crate) const SUBSTRING_AST_KIND: &str = "substring"; +pub(crate) const COALESCE_AST_KIND: &str = "coalesce"; +pub(crate) const IF_FUNC_AST_KIND: &str = "if_func"; +pub(crate) const CASE_AST_KIND: &str = "case"; +pub(crate) const TRY_CAST_AST_KIND: &str = "try_cast"; +pub(crate) const COUNT_AST_KIND: &str = "count"; +pub(crate) const IS_NULL_AST_KIND: &str = "is_null"; +pub(crate) const SET_OPERATION_AST_KINDS: [&str; 3] = ["union", "intersect", "except"]; +pub(crate) const CAST_AST_KINDS: [&str; 2] = ["cast", "try_cast"]; +pub(crate) const TYPE_PASSTHROUGH_AST_KINDS: [&str; 4] = + ["max", "min", "window_function", "within_group"]; +/// Python's `POLYGLOT_BOOLEAN_RESULT_KINDS`. +pub(crate) const BOOLEAN_RESULT_AST_KINDS: [&str; 18] = [ + "boolean", + "and", + "between", + "eq", + "exists", + "gt", + "gte", + "ilike", + "in", + "is", + "is_null", + "like", + "lt", + "lte", + "neq", + "not", + "or", + "regexp_like", +]; +pub(crate) const NULLIF_FUNCTION_NAME: &str = "NULLIF"; +pub(crate) const STRING_LITERAL_TYPE: &str = "string"; +pub(crate) const BINARY_OPERAND_COUNT: usize = 2; +/// The type Python's set operation slots give a bare NULL. +pub(crate) const NULL_SET_OPERATION_TYPE: &str = "__SQLBUILD_NULL_SET_OPERATION_TYPE__"; +pub(crate) const BOOLEAN_TYPE: &str = "BOOLEAN"; +pub(crate) const TEXT_TYPE: &str = "TEXT"; +pub(crate) const CUSTOM_TYPE_NAME: &str = "CUSTOM"; +pub(crate) const TIMESTAMP_TYPE_NAME: &str = "timestamp"; +pub(crate) const TIMESTAMP_TZ_TYPE: &str = "TIMESTAMPTZ"; +pub(crate) const DECIMAL_TYPE: &str = "DECIMAL"; +pub(crate) const VARCHAR_DATA_TYPES: [&str; 2] = ["var_char", "varchar"]; +/// Python's `_polyglot_type_name` names, matched case-sensitively as Python's dict is. +pub(crate) const POLYGLOT_TYPE_NAMES: [(&str, &str); 13] = [ + ("big_int", "BIGINT"), + ("bool", "BOOLEAN"), + ("boolean", "BOOLEAN"), + ("date", "DATE"), + ("decimal", "DECIMAL"), + ("double", "DOUBLE"), + ("float", "FLOAT"), + ("int", "INT"), + ("integer", "INT"), + ("text", "TEXT"), + ("timestamp", "TIMESTAMP"), + ("var_char", "TEXT"), + ("varchar", "TEXT"), +]; +/// Python's join sides that make relations nullable. +pub(crate) const JOIN_LEFT: &str = "LEFT"; +pub(crate) const JOIN_RIGHT: &str = "RIGHT"; +pub(crate) const JOIN_FULL: &str = "FULL"; +/// Ids of the adapter nullability rules Python registers, by the function it calls. +pub(crate) const FIRST_ARG_RULE: &str = "first_arg"; +pub(crate) const CONDITIONAL_RESULT_RULE: &str = "conditional_result"; +pub(crate) const NON_NULL_NULLABILITY: &str = "non_null"; +pub(crate) const NULLABLE_NULLABILITY: &str = "nullable"; diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finish_analysis_session.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finish_analysis_session.rs index f7a4fec8b3..11185a1ad6 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finish_analysis_session.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finish_analysis_session.rs @@ -1,8 +1,10 @@ //! Collect a finished native model analysis session's outcomes. -use crate::assembly::analysis_session::models::{AnalysisSession, SessionOutcome}; +use crate::assembly::analysis_session::models::{AnalysisSession, FinishedSession, SessionOutcome}; -/// Every model's outcome and the binding catalog changes Python records. -pub fn finish_analysis_session(session: AnalysisSession) -> Result { +/// Every model's outcome and catalog changes, and the session kept for later pivot proofs. +pub fn finish_analysis_session( + session: AnalysisSession, +) -> Result<(SessionOutcome, FinishedSession), String> { session.finish() } diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_fact_models.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_fact_models.rs new file mode 100644 index 0000000000..13692c612d --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_fact_models.rs @@ -0,0 +1,8 @@ +//! The models whose output names and lineage a finished analysis session kept. + +use crate::assembly::analysis_session::models::FinishedSession; + +/// Names of the models whose facts the session kept, in no particular order. +pub fn finished_fact_models(session: &FinishedSession) -> Vec { + session.models.keys().cloned().collect() +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_model_facts.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_model_facts.rs new file mode 100644 index 0000000000..bac994679b --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/finished_model_facts.rs @@ -0,0 +1,11 @@ +//! The output names and lineage a finished analysis session kept for compiled models. + +use crate::assembly::analysis_session::models::{FinishedSession, SessionModelFacts}; + +/// The named model's facts, or None where the session kept none for it. +pub fn finished_model_facts<'a>( + session: &'a FinishedSession, + name: &str, +) -> Option<&'a SessionModelFacts> { + session.models.get(name) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/mod.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/mod.rs index 6c5394355c..8906d2668a 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/mod.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/mod.rs @@ -1,6 +1,11 @@ pub mod expression_shapes; pub mod finish_analysis_session; -pub mod prove_dynamic_contract; +pub mod finished_fact_models; +pub mod finished_model_facts; +pub mod prove_dynamic_contracts; +pub mod prove_finished_dynamic_contracts; pub mod provide_deferred_analyses; +pub mod recover_cte_facts; pub mod run_analysis_session; +pub mod session_sharing; pub mod start_analysis_session; diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contract.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contract.rs deleted file mode 100644 index 96759642d4..0000000000 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contract.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Python's `analyze_dynamic_column_contract` for one model outside the analysis session. - -use crate::assembly::analysis_session::_helpers::dynamic_pivot::{PivotFacts, pivot_outcome}; -use crate::assembly::analysis_session::constants::PIVOT_WORKER_STACK_BYTES; -use crate::assembly::analysis_session::models::{PivotOutcome, PivotRequest}; - -/// The model's proof, or a deferral where Python's result is not reproduced exactly. -pub fn prove_dynamic_contract(request: &PivotRequest) -> Result { - let facts = PivotFacts { - dialect: &request.dialect, - column_types: &request.column_types, - authoritative_types: &request.authoritative_types, - column_nullability: &request.column_nullability, - families_by_table: &request.families_by_table, - }; - std::thread::scope(|scope| { - std::thread::Builder::new() - .stack_size(PIVOT_WORKER_STACK_BYTES) - .spawn_scoped(scope, || { - pivot_outcome(&request.sql, &request.families, &facts) - }) - .map_err(|error| error.to_string())? - .join() - .map_err(|_| "the native dynamic pivot proof panicked".to_owned()) - }) -} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contracts.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contracts.rs new file mode 100644 index 0000000000..bbbb199898 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_dynamic_contracts.rs @@ -0,0 +1,17 @@ +//! Python's `analyze_dynamic_column_contract` for models no analysis session analysed. + +use crate::assembly::analysis_session::_helpers::dynamic_pivot::pivot_outcomes; +use crate::assembly::analysis_session::constants::PIVOT_WORKER_STACK_BYTES; +use crate::assembly::analysis_session::models::{PivotBatchRequest, PivotOutcome}; + +/// Each model's proof in order; a model whose proof panics is deferred to Python. +pub fn prove_dynamic_contracts(request: &PivotBatchRequest) -> Result, String> { + std::thread::scope(|scope| { + std::thread::Builder::new() + .stack_size(PIVOT_WORKER_STACK_BYTES) + .spawn_scoped(scope, || pivot_outcomes(&request.models, &request.tables)) + .map_err(|error| error.to_string())? + .join() + .map_err(|_| "the native dynamic pivot proofs panicked".to_owned()) + }) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_finished_dynamic_contracts.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_finished_dynamic_contracts.rs new file mode 100644 index 0000000000..28a9f22db8 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/prove_finished_dynamic_contracts.rs @@ -0,0 +1,13 @@ +//! Python's `analyze_dynamic_column_contract` for models outside a finished analysis session. + +use crate::assembly::analysis_session::_helpers::dynamic_pivot::pooled_pivot_outcomes; +use crate::assembly::analysis_session::models::{FinishedSession, PivotModel, PivotOutcome}; + +/// Each model's proof in order from the session's own tables; a panicking proof is deferred. +pub fn prove_finished_dynamic_contracts( + session: &FinishedSession, + models: &[PivotModel], +) -> Result, String> { + let pool = session.pool.as_ref().map_err(Clone::clone)?; + Ok(pooled_pivot_outcomes(pool, models, &session.tables)) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/recover_cte_facts.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/recover_cte_facts.rs new file mode 100644 index 0000000000..84aace7ca4 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/recover_cte_facts.rs @@ -0,0 +1,47 @@ +//! Python's CTE pass-through facts and filtered non-null outputs for one query. + +use crate::assembly::analysis_session::_helpers::cte_facts::{ + Recovery, RecoveryInput, RecoveryProfile, recovery, +}; +use crate::assembly::analysis_session::constants::CTE_FACT_WORKER_STACK_BYTES; +use crate::assembly::analysis_session::models::{CteFactRequest, CteFacts}; + +/// The facts enrichment recovers for the query, or why they are left to Python. +pub fn recover_cte_facts(request: &CteFactRequest) -> Result { + std::thread::scope(|scope| { + std::thread::Builder::new() + .stack_size(CTE_FACT_WORKER_STACK_BYTES) + .spawn_scoped(scope, || recovered_facts(request)) + .map_err(|error| error.to_string())? + .join() + .map_err(|_| "native CTE fact recovery panicked".to_owned())? + }) +} + +fn recovered_facts(request: &CteFactRequest) -> Result { + let recovered: Recovery = recovery(&RecoveryInput { + cleaned_sql: &request.cleaned_sql, + input_schemas: &request.input_schemas, + recover: request.recover, + null_filter: request.null_filter, + profile: RecoveryProfile { + dialect: &request.dialect, + function_return_types: &request.function_return_types, + rules: request.nullability_rules.as_ref(), + }, + })?; + let mut direct_outputs: Vec = recovered.direct_outputs.into_iter().collect(); + direct_outputs.sort_unstable(); + let mut non_null_outputs: Vec = recovered.non_null_outputs.into_iter().collect(); + non_null_outputs.sort_unstable(); + Ok(CteFacts { + types: recovered.types, + nullability: recovered + .nullability + .into_iter() + .map(|(name, nullability)| (name, nullability.to_owned())) + .collect(), + direct_outputs, + non_null_outputs, + }) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/main/session_sharing.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/session_sharing.rs new file mode 100644 index 0000000000..3b67b99626 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/main/session_sharing.rs @@ -0,0 +1,8 @@ +//! How many of a session's analysed models shared a query, and how many it re-analysed. + +use crate::assembly::analysis_session::models::AnalysisSession; + +/// `(shared members, shared members re-analysed alone)` across the session's batches so far. +pub fn session_sharing(session: &AnalysisSession) -> (usize, usize) { + session.catalog.sharing() +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/models.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/models.rs index d10d56c0ad..4573b84160 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/models.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/models.rs @@ -1,10 +1,13 @@ //! Plain-data request, deferrals and outcomes of the native model analysis session. use std::collections::HashMap; +use std::sync::Arc; + +use rayon::ThreadPool; use crate::assembly::analysis_session::_helpers::catalog_state::SessionCatalog; use crate::assembly::analysis_session::_helpers::mappings::ShapeTable; -use crate::assembly::analysis_session::types::{Pairs, Shapes}; +use crate::assembly::analysis_session::types::{OutputSources, Pairs, Shapes}; use crate::semantic_validation::types::DiagnosticRow; /// One `ref`, `source`, `seed`, `table_fn` or `udf` call a model's SQL makes. @@ -61,18 +64,45 @@ pub struct ContractProof { pub bare_dynamic_pivot: bool, } -/// One model's dynamic pivot proof inputs, for a model the session does not analyse. +/// The relation facts every dynamic pivot proof reads: Python's tables before analysis. #[derive(Debug, Clone, Default)] -pub struct PivotRequest { +pub struct PivotTables { pub dialect: String, pub column_types: Shapes, pub authoritative_types: Shapes, pub column_nullability: Shapes, pub families_by_table: Vec<(String, Vec)>, +} + +/// One model's pivot SQL and declared families. +#[derive(Debug, Clone, Default)] +pub struct PivotModel { pub sql: String, pub families: Vec, } +/// Dynamic pivot proofs for models no session analysed. +#[derive(Debug, Clone, Default)] +pub struct PivotBatchRequest { + pub tables: PivotTables, + pub models: Vec, +} + +/// A finished session's pivot tables, analysis pool and model facts, kept for later stages. +#[derive(Debug)] +pub struct FinishedSession { + pub(crate) tables: PivotTables, + pub(crate) pool: Result, String>, + pub(crate) models: HashMap, +} + +/// A compiled model's output names and lineage from an analysis the session completed natively. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SessionModelFacts { + pub columns: Option>, + pub lineage: OutputSources, +} + /// A model's dynamic pivot proof: none declared, left to Python, or proven natively. #[derive(Debug, Clone, PartialEq, Eq)] pub enum PivotOutcome { @@ -89,6 +119,8 @@ pub struct SessionRequest { /// Whether published shapes keep authored quoting, Python's `inferred_binding_shape` test. pub case_sensitive_shapes: bool, pub function_return_types: Pairs, + /// Adapter nullability rules as `(function name, rule id)`; None where one is not Python's. + pub nullability_rules: Option, pub rich_type_inference: bool, pub column_types: Shapes, pub column_nullability: Shapes, @@ -257,3 +289,30 @@ pub struct AnalysisSession { pub(crate) publications: Shapes, pub(crate) failures: Vec, } + +/// One query's CTE fact recovery, as Python's compact enrichment runs it. +#[derive(Debug, Clone)] +pub struct CteFactRequest { + pub cleaned_sql: String, + pub dialect: String, + /// Input relation types; every input column's nullability is unknown, as in enrichment. + pub input_schemas: Shapes, + pub function_return_types: Pairs, + /// Adapter nullability rules as `(function name, rule id)`; None where one is not Python's. + pub nullability_rules: Option, + /// Whether Python runs `_polyglot_cte_passthrough_facts` past its early return. + pub recover: bool, + /// Whether a filter reads NULL, so Python looks for filtered non-null outputs. + pub null_filter: bool, +} + +/// Python's recovered CTE pass-through facts and filtered non-null outputs for one query. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CteFacts { + pub types: Pairs, + pub nullability: Pairs, + /// Sorted direct CTE output names. + pub direct_outputs: Vec, + /// Sorted outputs a filter proves non-null. + pub non_null_outputs: Vec, +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/helpers.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/helpers.rs index 1f274fdfc1..32163b81f1 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/helpers.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/helpers.rs @@ -1,14 +1,20 @@ +use std::collections::HashMap; + +use crate::assembly::analysis_session::_helpers::cte_facts::{ + Recovery, RecoveryInput, RecoveryProfile, recovery, +}; use crate::assembly::analysis_session::_helpers::mappings::catalog_relations; use crate::assembly::analysis_session::main::finish_analysis_session::finish_analysis_session; +use crate::assembly::analysis_session::main::finished_model_facts::finished_model_facts; use crate::assembly::analysis_session::main::provide_deferred_analyses::provide_deferred_analyses; use crate::assembly::analysis_session::main::run_analysis_session::run_analysis_session; use crate::assembly::analysis_session::main::start_analysis_session::start_analysis_session; use crate::assembly::analysis_session::models::{ AnalysisSession, ColumnFact, ContractProof, Deferral, DeferredAnalysis, DynamicFamily, - ModelOutcome, ModelReference, ModelRequest, PivotOutcome, PivotRequest, SessionRequest, - SessionStep, + FinishedSession, ModelOutcome, ModelReference, ModelRequest, PivotBatchRequest, PivotModel, + PivotOutcome, PivotTables, SessionModelFacts, SessionRequest, SessionStep, }; -use crate::assembly::analysis_session::tests::test_types::ModelSpec; +use crate::assembly::analysis_session::tests::test_types::{ModelSpec, RecoveredFacts}; use crate::assembly::analysis_session::types::{Pairs, Shapes}; use crate::semantic_validation::models::{CatalogInput, ProjectCatalog}; @@ -95,6 +101,7 @@ pub(crate) fn orders_request(models: Vec) -> SessionRequest { dialect: "duckdb".to_owned(), case_sensitive_shapes: false, function_return_types: Vec::new(), + nullability_rules: Some(Vec::new()), rich_type_inference: true, column_types: raw_orders.clone(), column_nullability: shapes(&[( @@ -113,11 +120,11 @@ pub(crate) fn started(request: SessionRequest) -> AnalysisSession { start_analysis_session(request, &catalog).expect("the models form no cycle") } -/// Run to completion, answering every deferral with `answer`; return the steps and outcomes. +/// Run to completion, answering every deferral with `answer`: the steps, outcomes and session. pub(crate) fn completed( mut session: AnalysisSession, answer: fn(&Deferral) -> DeferredAnalysis, -) -> (Vec, Vec) { +) -> (Vec, Vec, FinishedSession) { let mut done: bool = false; let steps: Vec = std::iter::from_fn(|| { (!done).then(|| { @@ -131,8 +138,8 @@ pub(crate) fn completed( }) }) .collect(); - let outcome = finish_analysis_session(session).expect("the session finished"); - (steps, outcome.models) + let (outcome, finished) = finish_analysis_session(session).expect("the session finished"); + (steps, outcome.models, finished) } /// `name type nullability` per column, or `failed` when analysis did not succeed. @@ -205,7 +212,7 @@ pub(crate) fn model_requests(models: &[ModelSpec]) -> Vec { /// Run `models` over the orders request: each step's lines and each model's description. pub(crate) fn session_lines(models: &[ModelSpec]) -> (Vec>, Vec>) { - let (steps, outcomes) = completed( + let (steps, outcomes, _) = completed( started(orders_request(model_requests(models))), empty_answer, ); @@ -215,12 +222,35 @@ pub(crate) fn session_lines(models: &[ModelSpec]) -> (Vec>, Vec Vec { + let (_, _, finished) = completed( + started(orders_request(model_requests(models))), + empty_answer, + ); + models + .iter() + .map(|(name, ..)| { + finished_model_facts(&finished, name).map_or("none".to_owned(), fact_line) + }) + .collect() +} + +fn fact_line(facts: &SessionModelFacts) -> String { + let lineage: Vec = facts + .lineage + .iter() + .map(|(output, sources)| format!("{output}<-{sources:?}")) + .collect(); + format!("{:?} {}", facts.columns, lineage.join(" ")) +} + +/// Proofs over typed `raw_orders` and pivot `status_amounts`: the model, then a family-less one. pub(crate) fn pivot_request( dialect: &str, sql: &str, family: Option<(&str, &str, &str)>, -) -> PivotRequest { +) -> PivotBatchRequest { let raw_orders: Shapes = shapes(&[( "raw_orders", &[ @@ -237,17 +267,36 @@ pub(crate) fn pivot_request( }) .into_iter() .collect(); - PivotRequest { - dialect: dialect.to_owned(), - column_types: [raw_orders.clone(), upstream].concat(), - authoritative_types: raw_orders, - column_nullability: shapes(&[("raw_orders", &[("customer_id", "non_null")])]), - families_by_table: vec![( - "status_amounts".to_owned(), - vec![amounts("status", "amount", "MAX")], - )], - sql: sql.to_owned(), - families, + PivotBatchRequest { + tables: PivotTables { + dialect: dialect.to_owned(), + column_types: [raw_orders.clone(), upstream].concat(), + authoritative_types: raw_orders, + column_nullability: shapes(&[("raw_orders", &[("customer_id", "non_null")])]), + families_by_table: vec![( + "status_amounts".to_owned(), + vec![amounts("status", "amount", "MAX")], + )], + }, + models: vec![ + PivotModel { + sql: sql.to_owned(), + families, + }, + PivotModel { + sql: "SELECT 1".to_owned(), + families: Vec::new(), + }, + ], + } +} + +/// A finished session holding `tables` and an analysis pool. +pub(crate) fn finished_session(tables: PivotTables) -> FinishedSession { + FinishedSession { + tables, + pool: catalog("duckdb", &Vec::new()).analysis_pool(), + models: HashMap::new(), } } @@ -297,3 +346,52 @@ pub(crate) fn proven( bare_dynamic_pivot: bare, }) } + +/// Python's recovery over `orders` for a contract-enforced model whose filter reads NULL. +pub(crate) fn recovered_facts(sql: &str) -> Option<(Pairs, Pairs, Vec, Vec)> { + let input_schemas: Shapes = shapes(&[( + "orders", + &[ + ("order_id", "INTEGER"), + ("amount", "DOUBLE"), + ("status", "VARCHAR"), + ], + )]); + let rules: Pairs = pairs(&[("UPPER", "first_arg")]); + let recovered: Recovery = recovery(&RecoveryInput { + cleaned_sql: sql, + input_schemas: &input_schemas, + recover: true, + null_filter: true, + profile: RecoveryProfile { + dialect: "duckdb", + function_return_types: &Vec::new(), + rules: Some(&rules), + }, + }) + .ok()?; + let mut direct: Vec = recovered.direct_outputs.into_iter().collect(); + direct.sort(); + let mut non_null: Vec = recovered.non_null_outputs.into_iter().collect(); + non_null.sort(); + let nullability: Pairs = recovered + .nullability + .into_iter() + .map(|(name, value)| (name, value.to_owned())) + .collect(); + Some((recovered.types, nullability, direct, non_null)) +} + +/// The expected recovery as owned values. +pub(crate) fn expected_facts( + facts: Option, +) -> Option<(Pairs, Pairs, Vec, Vec)> { + facts.map(|(types, nullability, direct, non_null)| { + ( + pairs(types), + pairs(nullability), + direct.iter().map(|name| (*name).to_owned()).collect(), + non_null.iter().map(|name| (*name).to_owned()).collect(), + ) + }) +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_analysis_session.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_analysis_session.rs index c56625f012..4d37071e59 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_analysis_session.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_analysis_session.rs @@ -1,11 +1,13 @@ -use crate::assembly::analysis_session::main::prove_dynamic_contract::prove_dynamic_contract; +use crate::assembly::analysis_session::main::prove_dynamic_contracts::prove_dynamic_contracts; +use crate::assembly::analysis_session::main::prove_finished_dynamic_contracts::prove_finished_dynamic_contracts; use crate::assembly::analysis_session::main::start_analysis_session::start_analysis_session; use crate::assembly::analysis_session::models::PivotOutcome; use crate::assembly::analysis_session::tests::helpers::{ - catalog, failed, model_requests, orders_request, pivot_request, proven, session_lines, + catalog, expected_facts, fact_lines, failed, finished_session, model_requests, orders_request, + pivot_request, proven, recovered_facts, session_lines, }; use crate::assembly::analysis_session::tests::test_types::{ - PivotTestCase, SessionTestCase, UnscheduledTestCase, + CteRecoveryTestCase, PivotTestCase, SessionFactsTestCase, SessionTestCase, UnscheduledTestCase, }; #[test] @@ -125,6 +127,64 @@ fn given_models_when_running_the_session_then_defers_and_publishes_as_python_doe } } +#[test] +fn given_finished_sessions_when_reading_model_facts_then_keeps_only_native_successes() { + let test_cases = [ + SessionFactsTestCase { + description: "native lineage keeps output names and sources", + models: &[ + ( + "stg_orders", + "SELECT order_id, amount * 2 AS doubled FROM __source(\"raw_orders\")", + &["raw_orders"], + &[], + ), + ( + "orders_bad", + "SELECT missing_column FROM __source(\"raw_orders\")", + &["raw_orders"], + &[], + ), + ], + expected_facts: &[ + "Some([\"order_id\", \"doubled\"]) \ + order_id<-[(\"raw_orders\", \"order_id\")] \ + doubled<-[(\"raw_orders\", \"amount\")]", + "Some([\"missing_column\"]) missing_column<-[(\"raw_orders\", \"missing_column\")]", + ], + }, + SessionFactsTestCase { + description: "a model Python analysed keeps no session facts", + models: &[ + ( + "events", + "SELECT event_id FROM __source(\"raw_events\")", + &["raw_events"], + &[], + ), + ( + "events_mart", + "SELECT event_id, 1 AS one FROM __ref(\"events\")", + &[], + &["events"], + ), + ], + expected_facts: &[ + "Some([\"event_id\"]) event_id<-[(\"raw_events\", \"event_id\")]", + "none", + ], + }, + ]; + for test_case in test_cases { + assert_eq!( + fact_lines(test_case.models), + test_case.expected_facts, + "{}", + test_case.description + ); + } +} + #[test] fn given_unschedulable_models_when_starting_then_python_analyses() { let test_cases = [ @@ -281,11 +341,86 @@ fn given_dynamic_pivots_when_proving_then_matches_python_or_defers() { ]; for test_case in test_cases { let request = pivot_request(test_case.dialect, test_case.sql, test_case.family); + let session = finished_session(request.tables.clone()); + + let standalone = prove_dynamic_contracts(&request).expect("the proofs run"); + let in_session = + prove_finished_dynamic_contracts(&session, &request.models).expect("the proofs run"); + + assert_eq!( + standalone, + vec![test_case.expected_outcome.clone(), PivotOutcome::Absent], + "{}", + test_case.description + ); + assert_eq!( + in_session, + vec![test_case.expected_outcome, PivotOutcome::Absent], + "{}", + test_case.description + ); + } +} - let outcome = prove_dynamic_contract(&request).expect("the proof runs"); +#[test] +fn given_cte_reads_when_recovering_facts_then_matches_python_or_defers() { + let test_cases = [ + CteRecoveryTestCase { + description: "direct CTE reads keep input and cast types", + sql: "WITH base AS (SELECT order_id, CAST(amount AS DECIMAL(10, 2)) AS amount \ + FROM orders) SELECT order_id, amount FROM base", + expected_facts: Some(( + &[("order_id", "INTEGER"), ("amount", "DECIMAL(10, 2)")], + &[], + &["amount", "order_id"], + &[], + )), + }, + CteRecoveryTestCase { + description: "literals and filtered columns are non-null through an aliased CTE", + sql: "WITH base AS (SELECT 'x' AS tag, UPPER(status) AS up, order_id FROM orders \ + WHERE order_id IS NOT NULL) SELECT b.tag, b.up, b.order_id FROM base AS b", + expected_facts: Some(( + &[("order_id", "INTEGER")], + &[("tag", "non_null"), ("order_id", "non_null")], + &["order_id", "tag", "up"], + &[], + )), + }, + CteRecoveryTestCase { + description: "a set operation branch with an unnamed NULL proves nothing", + sql: "WITH u AS (SELECT order_id AS k, status AS s FROM orders UNION ALL \ + SELECT NULL, 'y') SELECT k, s FROM u", + expected_facts: Some((&[], &[], &["k", "s"], &[])), + }, + CteRecoveryTestCase { + description: "a star with EXCLUDE and a joined relation", + sql: "WITH a AS (SELECT * EXCLUDE (amount) FROM orders) SELECT o.status, a.order_id \ + FROM a LEFT JOIN orders AS o ON a.order_id = o.order_id", + expected_facts: Some(( + &[("status", "VARCHAR"), ("order_id", "INTEGER")], + &[], + &["order_id", "status"], + &[], + )), + }, + CteRecoveryTestCase { + description: "no CTE leaves only the filtered non-null outputs", + sql: "SELECT order_id, status FROM orders WHERE order_id IS NOT NULL", + expected_facts: Some((&[], &[], &[], &["order_id"])), + }, + CteRecoveryTestCase { + description: "non-ASCII names Python casefolds differently", + sql: "WITH b\u{e4}se AS (SELECT order_id FROM orders) SELECT order_id FROM b\u{e4}se", + expected_facts: None, + }, + ]; + for test_case in test_cases { + let facts = recovered_facts(test_case.sql); assert_eq!( - outcome, test_case.expected_outcome, + facts, + expected_facts(test_case.expected_facts), "{}", test_case.description ); diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_types.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_types.rs index c09b783048..68df851dab 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_types.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/tests/test_types.rs @@ -17,6 +17,13 @@ pub(crate) struct SessionTestCase { pub(crate) expected_outcomes: &'static [&'static [&'static str]], } +pub(crate) struct SessionFactsTestCase { + pub(crate) description: &'static str, + pub(crate) models: &'static [ModelSpec], + /// `fact_lines` of each model, in request order. + pub(crate) expected_facts: &'static [&'static str], +} + pub(crate) struct UnscheduledTestCase { pub(crate) description: &'static str, pub(crate) models: &'static [ModelSpec], @@ -51,3 +58,18 @@ pub(crate) struct PivotTestCase { pub(crate) family: Option<(&'static str, &'static str, &'static str)>, pub(crate) expected_outcome: PivotOutcome, } + +/// Types, nullabilities, direct CTE outputs and filtered non-null outputs, in Python's order. +pub(crate) type RecoveredFacts = ( + &'static [(&'static str, &'static str)], + &'static [(&'static str, &'static str)], + &'static [&'static str], + &'static [&'static str], +); + +pub(crate) struct CteRecoveryTestCase { + pub(crate) description: &'static str, + pub(crate) sql: &'static str, + /// None where the recovery defers to Python. + pub(crate) expected_facts: Option, +} diff --git a/crates/sqlbuild-analysis/src/assembly/analysis_session/types.rs b/crates/sqlbuild-analysis/src/assembly/analysis_session/types.rs index 5c36906409..0dbac8f6a5 100644 --- a/crates/sqlbuild-analysis/src/assembly/analysis_session/types.rs +++ b/crates/sqlbuild-analysis/src/assembly/analysis_session/types.rs @@ -4,3 +4,5 @@ pub type Pairs = Vec<(String, String)>; /// Ordered relation shapes in Python dict order. pub type Shapes = Vec<(String, Pairs)>; +/// `(output column, [(resource name, column name)])` per output, in lineage order. +pub type OutputSources = Vec<(String, Vec<(String, String)>)>; diff --git a/crates/sqlbuild-analysis/src/assembly/project/main/check_sql_syntax.rs b/crates/sqlbuild-analysis/src/assembly/project/main/check_sql_syntax.rs new file mode 100644 index 0000000000..a2604be080 --- /dev/null +++ b/crates/sqlbuild-analysis/src/assembly/project/main/check_sql_syntax.rs @@ -0,0 +1,28 @@ +//! Whether Python's syntax validation accepts every SQL string, stopping at the first it rejects. + +use sqlbuild_core::constants::PANIC_MESSAGE; +use sqlbuild_core::panics::main::catch_compiler_panic::catch_compiler_panic; + +use crate::assembly::project::_helpers::syntax::syntax_valid; +use crate::assembly::project::constants::PANIC_DEFERRAL; +use crate::assembly::project::models::SyntaxCheck; + +/// True when every check parses, false at the first Python rejects, Err to let Python decide. +pub fn check_sql_syntax(dialect: &str, checks: &[SyntaxCheck]) -> Result { + catch_compiler_panic(|| all_valid(dialect, checks)).map_err(|kind| { + if kind == PANIC_MESSAGE { + PANIC_DEFERRAL.to_owned() + } else { + kind + } + }) +} + +fn all_valid(dialect: &str, checks: &[SyntaxCheck]) -> Result { + for check in checks { + if !syntax_valid(check, dialect)? { + return Ok(false); + } + } + Ok(true) +} diff --git a/crates/sqlbuild-analysis/src/assembly/project/main/mod.rs b/crates/sqlbuild-analysis/src/assembly/project/main/mod.rs index d53093ec5a..d35ca0b269 100644 --- a/crates/sqlbuild-analysis/src/assembly/project/main/mod.rs +++ b/crates/sqlbuild-analysis/src/assembly/project/main/mod.rs @@ -1 +1,2 @@ pub mod assemble_project_resources; +pub mod check_sql_syntax; diff --git a/crates/sqlbuild-analysis/src/assembly/project/tests/helpers.rs b/crates/sqlbuild-analysis/src/assembly/project/tests/helpers.rs index 5f245315d3..e983316a09 100644 --- a/crates/sqlbuild-analysis/src/assembly/project/tests/helpers.rs +++ b/crates/sqlbuild-analysis/src/assembly/project/tests/helpers.rs @@ -6,6 +6,7 @@ use crate::assembly::project::_helpers::deps::audit_deps; use crate::assembly::project::_helpers::syntax::syntax_valid; use crate::assembly::project::_helpers::targets::{managed_source, seed_target}; use crate::assembly::project::_helpers::templates::TemplateInputs; +use crate::assembly::project::main::check_sql_syntax::check_sql_syntax; use crate::assembly::project::models::{ AuditFacts, InputRead, Namespace, Reference, SeedDefaults, SeedFacts, SourceFacts, SyntaxCheck, TargetNamespace, Variable, @@ -114,6 +115,17 @@ pub(crate) fn valid(sql: &str, placeholders: &[(&str, &str)], dialect: &str) -> .ok() } +pub(crate) fn all_valid(sqls: &[&str]) -> Option { + let checks: Vec = sqls + .iter() + .map(|sql| SyntaxCheck { + sql: (*sql).to_owned(), + placeholders: vec![("x".to_owned(), "1".to_owned())], + }) + .collect(); + check_sql_syntax("generic", &checks).ok() +} + pub(crate) fn namespace(expected: ExpectedNamespace) -> Namespace { let (database, schema, logical_database, logical_schema) = expected; Namespace { diff --git a/crates/sqlbuild-analysis/src/assembly/project/tests/test_project_assembly.rs b/crates/sqlbuild-analysis/src/assembly/project/tests/test_project_assembly.rs index e7a7b02ccc..184a8b3ff3 100644 --- a/crates/sqlbuild-analysis/src/assembly/project/tests/test_project_assembly.rs +++ b/crates/sqlbuild-analysis/src/assembly/project/tests/test_project_assembly.rs @@ -1,7 +1,10 @@ use crate::assembly::project::models::InputRead; -use crate::assembly::project::tests::helpers::{deps, namespace, seed, seed_reads, source, valid}; +use crate::assembly::project::tests::helpers::{ + all_valid, deps, namespace, seed, seed_reads, source, valid, +}; use crate::assembly::project::tests::test_types::{ - DepsTestCase, EnvironmentTestCase, SeedTestCase, SourceTestCase, SyntaxTestCase, keys, + DepsTestCase, EnvironmentTestCase, SeedTestCase, SourceTestCase, SyntaxBatchTestCase, + SyntaxTestCase, keys, }; #[test] @@ -287,3 +290,34 @@ fn given_environment_templates_when_resolving_seeds_then_matches_python_values_a assert_eq!(reads, test_case.expected_reads, "{}", test_case.description); } } + +#[test] +fn given_sql_batches_when_checking_syntax_then_stops_at_python_first_rejection_or_defers() { + let test_cases = [ + SyntaxBatchTestCase { + description: "every statement parses", + sqls: &["SELECT @@@x AS a", "SELECT 2"], + expected_valid: Some(true), + }, + SyntaxBatchTestCase { + description: "a later statement Python rejects", + sqls: &["SELECT 1", "SELECT FROM WHERE ("], + expected_valid: Some(false), + }, + SyntaxBatchTestCase { + description: "Python stops at the rejection before a statement native defers", + sqls: &["SELECT FROM WHERE (", "SELECT @@@x\u{e9}"], + expected_valid: Some(false), + }, + SyntaxBatchTestCase { + description: "a statement native defers before any rejection", + sqls: &["SELECT @@@x\u{e9}", "SELECT FROM WHERE ("], + expected_valid: None, + }, + ]; + for test_case in test_cases { + let valid = all_valid(test_case.sqls); + + assert_eq!(valid, test_case.expected_valid, "{}", test_case.description); + } +} diff --git a/crates/sqlbuild-analysis/src/assembly/project/tests/test_types.rs b/crates/sqlbuild-analysis/src/assembly/project/tests/test_types.rs index f39fb71bfd..ca67d431c2 100644 --- a/crates/sqlbuild-analysis/src/assembly/project/tests/test_types.rs +++ b/crates/sqlbuild-analysis/src/assembly/project/tests/test_types.rs @@ -73,3 +73,10 @@ pub(crate) struct EnvironmentTestCase { pub(crate) expected_schema: Option<&'static str>, pub(crate) expected_reads: Vec, } + +pub(crate) struct SyntaxBatchTestCase { + pub(crate) description: &'static str, + pub(crate) sqls: &'static [&'static str], + /// None where native defers to Python. + pub(crate) expected_valid: Option, +} diff --git a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/assembly.rs b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/assembly.rs new file mode 100644 index 0000000000..6836d3cf0f --- /dev/null +++ b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/assembly.rs @@ -0,0 +1,173 @@ +//! Python's `_assemble_compiled_sql_test` facts: name, targets, scope, case identity and P013s. + +use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use sqlbuild_sqltext::sql_scan::models::LexicalSyntax; + +use crate::compiler::_helpers::sql_tests::case_identity::case_fingerprint; +use crate::compiler::_helpers::sql_tests::macro_call_names::macro_call_names; +use crate::compiler::_helpers::sql_tests::mock_reads::{ + MockReadsRequest, mock_reading_helper_diagnostics, +}; +use crate::compiler::models::{ + AssembledSqlTestFacts, SqlTestAssemblyBatch, SqlTestAssemblyDeferral, SqlTestAssemblyModel, + SqlTestAssemblyOutcome, SqlTestAssemblyPayload, SqlTestAssemblyTest, SqlTestHelperDiagnostic, +}; + +const MODEL_RESOURCE: &str = "model"; +const TABLE_FUNCTION_RESOURCE: &str = "table_fn"; +const MACRO_MODE: &str = "macro"; +const UDF_MODE: &str = "udf"; +const UDF_REFERENCE_KIND: &str = "udf"; + +/// Each test's facts in request order, or the reason Python assembles it. +pub(crate) fn assemble_batch(batch: &SqlTestAssemblyBatch) -> Vec { + let tests_macros = batch.tests.iter().any(|test| { + matches!(&test.payload, SqlTestAssemblyPayload::Direct { mode, .. } if mode == MACRO_MODE) + }); + let macro_names: Vec = batch + .models + .iter() + .map(|model| match &model.unscanned_macro_source { + Some(sql) if tests_macros => macro_call_names(sql), + Some(_) => Ok(Vec::new()), + None => Ok(model.macro_deps.clone()), + }) + .collect(); + let project = Project { + models: &batch.models, + macro_names: ¯o_names, + syntax: &batch.lexical_syntax, + }; + batch + .tests + .par_iter() + .map(|test| match assemble(test, &project) { + Ok(facts) => SqlTestAssemblyOutcome::Assembled(facts), + Err(deferral) => SqlTestAssemblyOutcome::Deferred(deferral), + }) + .collect() +} + +/// A model's macro dependencies, or Python's scan of its pre-macro SQL when none were recorded. +type MacroNames = Result, SqlTestAssemblyDeferral>; + +struct Project<'a> { + models: &'a [SqlTestAssemblyModel], + macro_names: &'a [MacroNames], + syntax: &'a LexicalSyntax, +} + +fn assemble( + test: &SqlTestAssemblyTest, + project: &Project<'_>, +) -> Result { + let models = project.models; + let syntax = project.syntax; + let mut target_model_names: Vec = Vec::new(); + let mut tested_resources: Vec<(String, String)> = Vec::new(); + let mut diagnostics: Vec = Vec::new(); + let scope_deps: Vec<(&'static str, String)> = match &test.payload { + SqlTestAssemblyPayload::Direct { + mode, + tested_resource_names, + } => { + tested_resources = tested_resource_names + .iter() + .map(|name| (mode.clone(), name.clone())) + .collect(); + direct_scope_deps(mode, tested_resource_names, project)? + } + SqlTestAssemblyPayload::Model(payload) => { + if payload.has_macro_mocks { + return Err(SqlTestAssemblyDeferral::MacroMocks); + } + for name in payload + .expected_model_names + .iter() + .chain(&payload.assertion_target_model_names) + .chain(&payload.reference_target_model_names) + { + if !target_model_names.contains(name) { + target_model_names.push(name.clone()); + } + } + diagnostics = mock_reading_helper_diagnostics(&MockReadsRequest { + test, + payload, + models, + target_model_names: &target_model_names, + syntax, + })?; + target_model_names + .iter() + .map(|name| (MODEL_RESOURCE, name.clone())) + .collect() + } + }; + let case_fingerprint = match &test.case_name { + Some(case_name) => Some(case_fingerprint( + test, + case_name, + &scope_deps, + &tested_resources, + )?), + None => None, + }; + Ok(AssembledSqlTestFacts { + name: test_name(test), + scope_deps, + target_model_names, + case_fingerprint, + diagnostic_resource_name: non_empty(&test.block_name) + .unwrap_or(&test.relative_stem) + .to_owned(), + diagnostics, + }) +} + +fn non_empty(name: &Option) -> Option<&str> { + name.as_deref().filter(|name| !name.is_empty()) +} + +/// Python's `_resolve_test_name`. +fn test_name(test: &SqlTestAssemblyTest) -> String { + let parent = non_empty(&test.block_name).unwrap_or(&test.file_stem); + match &test.case_name { + Some(case_name) => format!("{parent} [{case_name}]"), + None => parent.to_owned(), + } +} + +/// Python's macro, UDF and table-function scope dependencies of a direct-logic test. +fn direct_scope_deps( + mode: &str, + tested_names: &[String], + project: &Project<'_>, +) -> Result, SqlTestAssemblyDeferral> { + let mut scope_deps: Vec<(&'static str, String)> = Vec::new(); + match mode { + MACRO_MODE => { + for (model, names) in project.models.iter().zip(project.macro_names) { + let names = names.as_ref().map_err(|deferral| *deferral)?; + if names.iter().any(|name| tested_names.contains(name)) { + scope_deps.push((MODEL_RESOURCE, model.name.clone())); + } + } + } + UDF_MODE => { + for model in project.models { + if model.references.iter().any(|reference| { + reference.kind == UDF_REFERENCE_KIND && tested_names.contains(&reference.name) + }) { + scope_deps.push((MODEL_RESOURCE, model.name.clone())); + } + } + } + _ => scope_deps.extend( + tested_names + .iter() + .map(|name| (TABLE_FUNCTION_RESOURCE, name.clone())), + ), + } + Ok(scope_deps) +} diff --git a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/case_identity.rs b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/case_identity.rs new file mode 100644 index 0000000000..4bbc98f63f --- /dev/null +++ b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/case_identity.rs @@ -0,0 +1,168 @@ +//! Python's `build_sql_test_case_fingerprint`: the version identity of one expanded test case. + +use sha2::{Digest, Sha256}; +use sqlbuild_core::json::main::dumps::dumps; +use sqlbuild_core::json::models::{JsonDialect, JsonInteger, JsonValue, StdlibJsonOptions}; + +use crate::compiler::models::{ + SqlTestAssemblyDeferral, SqlTestAssemblyTest, SqlTestParameterValue, +}; + +/// Python's default decimal context: precision and exponent limits `normalize()` applies. +const DECIMAL_PRECISION: usize = 28; +const DECIMAL_EMAX: i64 = 999_999; +const DECIMAL_EMIN: i64 = -999_999; + +/// The SHA-256 of Python's compact, ASCII, key-sorted JSON of the case's compile inputs. +pub(crate) fn case_fingerprint( + test: &SqlTestAssemblyTest, + case_name: &str, + scope_deps: &[(&'static str, String)], + tested_resources: &[(String, String)], +) -> Result { + let mut sorted_deps: Vec<(&str, &str)> = scope_deps + .iter() + .map(|(kind, name)| (*kind, name.as_str())) + .collect(); + sorted_deps.sort_unstable(); + let mut sorted_resources: Vec<(&str, &str)> = tested_resources + .iter() + .map(|(kind, name)| (kind.as_str(), name.as_str())) + .collect(); + sorted_resources.sort_unstable(); + let parameter_values: Vec = test + .parameter_values + .iter() + .map(|(name, value)| Ok(JsonValue::Array(vec![string(name), identity(value)?]))) + .collect::>()?; + let payload = JsonValue::Object(vec![ + ("source_path".to_owned(), string(&test.relative_path)), + ("block_index".to_owned(), integer(test.block_index)), + ("case_name".to_owned(), string(case_name)), + ( + "parameter_schema".to_owned(), + JsonValue::Array( + test.parameter_schema + .iter() + .map(|(name, kind, nullable)| { + JsonValue::Array(vec![ + string(name), + string(kind), + JsonValue::Bool(*nullable), + ]) + }) + .collect(), + ), + ), + ( + "parameter_values".to_owned(), + JsonValue::Array(parameter_values), + ), + ("expanded_sql".to_owned(), string(&test.sql_body)), + ("scope_deps".to_owned(), pairs(&sorted_deps)), + ("tested_resources".to_owned(), pairs(&sorted_resources)), + ]); + let dialect = JsonDialect::Stdlib(StdlibJsonOptions { + indent: None, + item_separator: ",".to_owned(), + key_separator: ":".to_owned(), + ensure_ascii: true, + sort_keys: true, + allow_nan: true, + }); + let encoded = + dumps(&payload, &dialect).map_err(|_| SqlTestAssemblyDeferral::UnencodableValue)?; + Ok(Sha256::digest(encoded.as_bytes()) + .iter() + .map(|byte| format!("{byte:02x}")) + .collect()) +} + +fn string(text: &str) -> JsonValue { + JsonValue::String(text.to_owned()) +} + +fn integer(value: i64) -> JsonValue { + JsonInteger::parse(&value.to_string()).map_or(JsonValue::Null, JsonValue::Integer) +} + +fn pairs(entries: &[(&str, &str)]) -> JsonValue { + JsonValue::Array( + entries + .iter() + .map(|(first, second)| JsonValue::Array(vec![string(first), string(second)])) + .collect(), + ) +} + +/// Python's `sql_value_identity`: `(kind, payload)` with decimals as normalized tuples. +fn identity(value: &SqlTestParameterValue) -> Result { + let (kind, payload) = match value { + SqlTestParameterValue::String(text) => ("string", string(text)), + SqlTestParameterValue::Integer(number) => ("integer", integer(*number)), + SqlTestParameterValue::Boolean(flag) => ("boolean", JsonValue::Bool(*flag)), + SqlTestParameterValue::Float(number) => ("float", JsonValue::Float(*number)), + SqlTestParameterValue::Decimal { + negative, + digits, + exponent, + } => ("decimal", normalized_decimal(*negative, digits, *exponent)?), + SqlTestParameterValue::Null => ("null", JsonValue::Null), + SqlTestParameterValue::List(items) => ("list", identities(items)?), + SqlTestParameterValue::Set(items) => ("set", identities(items)?), + SqlTestParameterValue::Object(entries) => ( + "object", + JsonValue::Array( + entries + .iter() + .map(|(key, item)| Ok(JsonValue::Array(vec![string(key), identity(item)?]))) + .collect::>()?, + ), + ), + }; + Ok(JsonValue::Array(vec![string(kind), payload])) +} + +fn identities(items: &[SqlTestParameterValue]) -> Result { + Ok(JsonValue::Array( + items.iter().map(identity).collect::>()?, + )) +} + +/// `Decimal.normalize().as_tuple()` where the default context neither rounds nor clamps. +fn normalized_decimal( + negative: bool, + digits: &[u8], + exponent: i64, +) -> Result { + let sign = integer(i64::from(negative)); + let first = digits.iter().position(|digit| *digit != 0); + let Some(first) = first else { + return Ok(JsonValue::Array(vec![ + sign, + JsonValue::Array(vec![integer(0)]), + integer(0), + ])); + }; + let significant = &digits[first..]; + let adjusted = exponent + i64::try_from(significant.len()).unwrap_or(i64::MAX) - 1; + if significant.len() > DECIMAL_PRECISION || !(DECIMAL_EMIN..=DECIMAL_EMAX).contains(&adjusted) { + return Err(SqlTestAssemblyDeferral::DecimalContext); + } + let mut end = significant.len(); + let mut normalized_exponent = exponent; + while significant[end - 1] == 0 && normalized_exponent < DECIMAL_EMAX { + end -= 1; + normalized_exponent += 1; + } + Ok(JsonValue::Array(vec![ + sign, + JsonValue::Array( + significant[..end] + .iter() + .map(|digit| integer(i64::from(*digit))) + .collect(), + ), + integer(normalized_exponent), + ])) +} diff --git a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/macro_call_names.rs b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/macro_call_names.rs new file mode 100644 index 0000000000..38c0421c61 --- /dev/null +++ b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/macro_call_names.rs @@ -0,0 +1,105 @@ +//! Python's `find_macro_call_names`: unique top-level macro call names in encounter order. + +use sqlbuild_sqltext::sql_scan::main::matching_paren::matching_paren; +use sqlbuild_sqltext::sql_scan::main::non_code_end::non_code_end; +use sqlbuild_sqltext::sql_scan::models::QuotePolicy; + +use crate::compiler::models::SqlTestAssemblyDeferral; + +/// Declaration calls that expansion substitutes rather than running as macros. +const DECLARATION_CALLS: [&str; 2] = ["enum", "const"]; + +type Scan = Result; + +/// The names Python's scan returns; text it raises on, or classifies by Unicode, is Python's. +pub(crate) fn macro_call_names(sql: &str) -> Scan> { + let bytes = sql.as_bytes(); + let mut names: Vec = Vec::new(); + let mut index = 0; + while index < bytes.len() { + match non_code_end(bytes, index, QuotePolicy::COMPILER) { + Ok(Some(end)) => { + index = end; + continue; + } + Ok(None) => {} + Err(_) => return Err(SqlTestAssemblyDeferral::MacroCallScan), + } + if bytes[index] != b'@' || !macro_call_at(bytes, index)? { + index += 1; + continue; + } + let name_end = identifier_end(bytes, index + 1)?; + let name = &sql[index + 1..name_end]; + if !names.iter().any(|known| known == name) { + names.push(name.to_owned()); + } + let open = space_end(bytes, name_end)?; + if bytes.get(open) != Some(&b'(') { + return Err(SqlTestAssemblyDeferral::MacroCallScan); + } + index = matching_paren(bytes, open, QuotePolicy::COMPILER) + .map_err(|_| SqlTestAssemblyDeferral::MacroCallScan)? + + 1; + } + names.retain(|name| !DECLARATION_CALLS.contains(&name.as_str())); + Ok(names) +} + +/// Python's `_is_macro_call_start`, which skips whitespace after each name character. +fn macro_call_at(bytes: &[u8], at: usize) -> Scan { + let Some(&first) = bytes.get(at + 1) else { + return Ok(false); + }; + if !ascii(first)? || !(first == b'_' || first.is_ascii_alphabetic()) { + return Ok(false); + } + let mut cursor = at + 2; + while let Some(&byte) = bytes.get(cursor) { + if !ascii(byte)? || !is_identifier_continue(byte) { + break; + } + cursor = space_end(bytes, cursor + 1)?; + } + Ok(bytes.get(cursor) == Some(&b'(')) +} + +fn identifier_end(bytes: &[u8], start: usize) -> Scan { + let mut cursor = start; + while let Some(&byte) = bytes.get(cursor) { + if !ascii(byte)? || !is_identifier_continue(byte) { + break; + } + cursor += 1; + } + Ok(cursor) +} + +/// Python's `str.isspace` skip; a non-ASCII character there is classified by Python. +fn space_end(bytes: &[u8], start: usize) -> Scan { + let mut cursor = start; + while let Some(&byte) = bytes.get(cursor) { + if !ascii(byte)? + || !matches!( + byte, + b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c | 0x1c..=0x1f + ) + { + break; + } + cursor += 1; + } + Ok(cursor) +} + +fn is_identifier_continue(byte: u8) -> bool { + byte == b'_' || byte.is_ascii_alphanumeric() +} + +fn ascii(byte: u8) -> Scan { + if byte.is_ascii() { + Ok(true) + } else { + Err(SqlTestAssemblyDeferral::MacroCallScan) + } +} diff --git a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mock_reads.rs b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mock_reads.rs new file mode 100644 index 0000000000..f381916286 --- /dev/null +++ b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mock_reads.rs @@ -0,0 +1,621 @@ +//! Python's `report_mocks_reading_referencing_helpers`: P013s for mocks reading referencing helpers. + +use std::collections::HashSet; + +use polyglot_sql::{ + ComplexityGuardOptions, Dialect, DialectType, Expression, ExpressionWalk, ParseOptions, +}; +use serde_json::Value; +use sqlbuild_sqltext::sql_references::main::extract_sql_references::extract_sql_references; +use sqlbuild_sqltext::sql_references::models::{ReferenceExtraction, SqlReference}; +use sqlbuild_sqltext::sql_scan::models::LexicalSyntax; + +use crate::compiler::_helpers::sql_tests::planning::MOCK_CTE_PREFIXES; +use crate::compiler::models::{ + SqlTestAssemblyDeferral, SqlTestAssemblyModel, SqlTestAssemblyModelPayload, + SqlTestAssemblyReference, SqlTestAssemblyTest, SqlTestCte, SqlTestHelperDiagnostic, +}; + +const REF_KIND: &str = "ref"; +const TABLE_FUNCTION_KIND: &str = "table_fn"; +const DBT_REF_KIND: &str = "dbt_ref"; +const RELATION_KINDS: [&str; 5] = [ + REF_KIND, + "source", + "seed", + DBT_REF_KIND, + TABLE_FUNCTION_KIND, +]; +/// Payload nesting past which the parsed tree is left to Python's `to_dict` walk. +const MAX_TREE_DEPTH: usize = 400; +/// The function call depth SQLBuild's Polyglot proxy allows `parse_one`. +const MAX_FUNCTION_CALL_DEPTH: usize = 512; + +type Deferrable = Result; + +/// A reference as compile carries it: the scanner's or a model input's. +#[derive(Clone)] +struct Reference { + kind: String, + name: String, + package: Option, +} + +/// One model test whose mocks may read referencing helpers, with the project's models. +pub(crate) struct MockReadsRequest<'a> { + pub(crate) test: &'a SqlTestAssemblyTest, + pub(crate) payload: &'a SqlTestAssemblyModelPayload, + pub(crate) models: &'a [SqlTestAssemblyModel], + pub(crate) target_model_names: &'a [String], + pub(crate) syntax: &'a LexicalSyntax, +} + +/// A Python dict by string key: a repeated key keeps its first position and takes the new value. +struct OrderedEntries { + entries: Vec<(String, T)>, +} + +impl OrderedEntries { + fn new() -> Self { + Self { + entries: Vec::new(), + } + } + + fn assign(&mut self, key: String, value: T) { + match self + .entries + .iter_mut() + .find(|(candidate, _)| *candidate == key) + { + Some(entry) => entry.1 = value, + None => self.entries.push((key, value)), + } + } + + fn get(&self, key: &str) -> Option<&T> { + self.entries + .iter() + .find(|(candidate, _)| candidate == key) + .map(|(_, value)| value) + } + + fn keys(&self) -> Vec { + self.entries.iter().map(|(key, _)| key.clone()).collect() + } +} + +/// Python's `SqlTestCteGraph`, keyed by case-folded CTE name in first-definition order. +struct CteGraph<'a> { + ctes: OrderedEntries<&'a SqlTestCte>, + reads: OrderedEntries>, + reader_reads: Vec, +} + +/// A located span as Python's `reference_call_location` reports it. +struct Span { + line: usize, + column: usize, + end_line: usize, + end_column: usize, +} + +impl CteGraph<'_> { + fn cte(&self, key: &str) -> Option<&SqlTestCte> { + self.ctes.get(key).copied() + } + + fn reads(&self, key: &str) -> &[String] { + self.reads.get(key).map_or(&[], Vec::as_slice) + } + + /// Python's `reachable_cte_keys`: breadth first, roots included, in visit order. + fn reachable(&self, roots: &[String]) -> Vec { + let mut pending: Vec = Vec::new(); + for root in roots { + if self.cte(root).is_some() { + pending.push(root.clone()); + } + } + let mut visited: Vec = Vec::new(); + for key in &pending { + if !visited.contains(key) { + visited.push(key.clone()); + } + } + let mut cursor = 0; + while cursor < pending.len() { + let key = pending[cursor].clone(); + cursor += 1; + for dependency in self.reads(&key) { + if !visited.contains(dependency) { + visited.push(dependency.clone()); + pending.push(dependency.clone()); + } + } + } + visited + } +} + +/// The P013 diagnostics Python reports for one model test, in report order. +pub(crate) fn mock_reading_helper_diagnostics( + request: &MockReadsRequest<'_>, +) -> Deferrable> { + let payload = request.payload; + let mut referencing: OrderedEntries = OrderedEntries::new(); + for cte in &payload.authored_ctes { + if is_mock_name(&cte.name) { + continue; + } + let first = references(&cte.sql_body, request.syntax)? + .into_iter() + .find(|reference| RELATION_KINDS.contains(&reference.kind.as_str())); + if let Some(reference) = first { + referencing.assign(ascii_fold(&cte.name)?, reference); + } + } + if referencing.entries.is_empty() { + return Ok(Vec::new()); + } + require_ascii(request.test, payload)?; + let readers: Vec<&SqlTestCte> = payload + .expected_ctes + .iter() + .chain(&payload.assertion_ctes) + .collect(); + let graph = cte_graph(&payload.authored_ctes, &readers)?; + let mut scanned: Vec<&str> = readers.iter().map(|cte| cte.sql_body.as_str()).collect(); + for key in read_helper_keys(&graph) { + if let Some(cte) = graph.cte(&key) { + scanned.push(cte.sql_body.as_str()); + } + } + let mut called_mocks: Vec = Vec::new(); + for sql in scanned { + for reference in references(sql, request.syntax)? { + called_mocks.extend(mock_keys(&reference)?); + } + } + let used = used_mock_keys(request, &graph, &called_mocks)?; + let mut diagnostics: Vec = Vec::new(); + for mock_key in used { + let mut helper: Option<(String, &Reference)> = None; + for key in graph.reachable(graph.reads(&mock_key)) { + if let Some(reference) = referencing.get(&key) { + helper = Some((key, reference)); + break; + } + } + let Some((helper_key, reference)) = helper else { + continue; + }; + let (Some(mock), Some(helper)) = (graph.cte(&mock_key), graph.cte(&helper_key)) else { + continue; + }; + let call = reference_call(reference); + let span = located(request.test, &helper.name, &call); + diagnostics.push(SqlTestHelperDiagnostic { + line: span.line, + column: span.column, + end_line: span.end_line, + end_column: span.end_column, + message: format!( + "SQL test mock '{}' reads helper CTE '{}', which calls {call}; mocks and \ + fixtures are defined before the models the test runs, so the helper cannot be \ + resolved for them", + mock.name, helper.name + ), + help: mock_reference_help(&mock.name, &call, reference), + }); + } + Ok(diagnostics) +} + +fn is_mock_name(name: &str) -> bool { + MOCK_CTE_PREFIXES + .iter() + .any(|prefix| name.starts_with(prefix)) +} + +/// Python's `str.casefold`, exact only on ASCII text. +fn ascii_fold(text: &str) -> Deferrable { + if text.is_ascii() { + Ok(text.to_ascii_lowercase()) + } else { + Err(SqlTestAssemblyDeferral::NonAsciiText) + } +} + +/// Python's folding, token and header patterns read only ASCII text exactly. +fn require_ascii( + test: &SqlTestAssemblyTest, + payload: &SqlTestAssemblyModelPayload, +) -> Deferrable<()> { + let ascii = test.contents.is_ascii() + && test.block_sql.is_ascii() + && payload + .authored_ctes + .iter() + .chain(&payload.expected_ctes) + .chain(&payload.assertion_ctes) + .all(|cte| cte.name.is_ascii() && cte.sql_body.is_ascii()); + if ascii { + Ok(()) + } else { + Err(SqlTestAssemblyDeferral::NonAsciiText) + } +} + +/// Python's `scan_sql_reference_calls(...).references`; a failing scan is Python's to raise. +fn references(sql: &str, syntax: &LexicalSyntax) -> Deferrable> { + match extract_sql_references(sql, syntax) { + ReferenceExtraction::Extracted(scan) => { + Ok(scan.references.into_iter().map(scanned).collect()) + } + ReferenceExtraction::Failed(_) | ReferenceExtraction::Deferred => { + Err(SqlTestAssemblyDeferral::ReferenceScan) + } + } +} + +fn scanned(reference: SqlReference) -> Reference { + Reference { + kind: reference.kind.to_owned(), + name: reference.name, + package: reference.package, + } +} + +fn model_reference(reference: &SqlTestAssemblyReference) -> Reference { + Reference { + kind: reference.kind.clone(), + name: reference.name.clone(), + package: reference.package.clone(), + } +} + +/// Python's `sql_test_cte_graph`. +fn cte_graph<'a>(authored: &'a [SqlTestCte], readers: &[&SqlTestCte]) -> Deferrable> { + let mut ctes: OrderedEntries<&'a SqlTestCte> = OrderedEntries::new(); + for cte in authored { + ctes.assign(ascii_fold(&cte.name)?, cte); + } + let keys: Vec = ctes.keys(); + let mut reads: OrderedEntries> = OrderedEntries::new(); + for (key, cte) in &ctes.entries { + let others: Vec = keys.iter().filter(|other| *other != key).cloned().collect(); + let cte_reads = match parsed_reads(&cte.sql_body, &others)? { + Some(parsed) => parsed, + None => token_reads(&cte.sql_body, &others), + }; + reads.assign(key.clone(), cte_reads); + } + let mut reader_reads: Vec = Vec::new(); + for reader in readers { + let parsed = match parsed_reads(&reader.sql_body, &keys)? { + Some(parsed) => parsed, + None => token_reads(&reader.sql_body, &keys), + }; + for key in parsed { + if !reader_reads.contains(&key) { + reader_reads.push(key); + } + } + } + Ok(CteGraph { + ctes, + reads, + reader_reads, + }) +} + +/// Python's `_parsed_reads`: unqualified reads of `keys` no nested CTE shadows, or None unparsed. +fn parsed_reads(sql: &str, keys: &[String]) -> Deferrable>> { + let folded = ascii_fold(sql)?; + if !keys.iter().any(|key| folded.contains(key.as_str())) { + return Ok(Some(Vec::new())); + } + let options = proxy_parse_options()?; + let Ok(mut statements) = Dialect::get(DialectType::Generic).parse_with_options(sql, &options) + else { + return Ok(None); + }; + if statements.len() != 1 { + return Ok(None); + } + let parsed: Expression = statements.remove(0); + let nested = defined_cte_keys(&parsed)?; + let mut reads: Vec = Vec::new(); + for node in parsed.dfs() { + let Expression::Table(table) = node else { + continue; + }; + if table.schema.is_some() || table.catalog.is_some() { + continue; + } + let key = ascii_fold(&table.name.name)?; + if keys.contains(&key) && !nested.contains(&key) && !reads.contains(&key) { + reads.push(key); + } + } + Ok(Some(reads)) +} + +/// The parse options SQLBuild's Polyglot proxy gives `parse_one`. +fn proxy_parse_options() -> Deferrable { + let guard: ComplexityGuardOptions = serde_json::from_value(serde_json::json!({ + "maxFunctionCallDepth": MAX_FUNCTION_CALL_DEPTH, + })) + .map_err(|_| SqlTestAssemblyDeferral::UnreadableTree)?; + Ok(ParseOptions { + complexity_guard: Some(guard), + }) +} + +/// Python's `_defined_cte_keys` over the serialized tree Python's `to_dict` returns. +fn defined_cte_keys(parsed: &Expression) -> Deferrable> { + let tree = serde_json::to_value(parsed).map_err(|_| SqlTestAssemblyDeferral::UnreadableTree)?; + let mut keys: HashSet = HashSet::new(); + let mut pending: Vec<(&Value, usize)> = vec![(&tree, 0)]; + while let Some((value, depth)) = pending.pop() { + if depth > MAX_TREE_DEPTH { + return Err(SqlTestAssemblyDeferral::UnreadableTree); + } + match value { + Value::Array(items) => pending.extend(items.iter().map(|item| (item, depth + 1))), + Value::Object(entries) => { + if let Some(Value::Array(ctes)) = entries.get("ctes") { + for cte in ctes { + if let Some(Value::String(name)) = cte + .get("alias") + .filter(|alias| alias.is_object()) + .and_then(|alias| alias.get("name")) + { + let _ = keys.insert(ascii_fold(name)?); + } + } + } + pending.extend(entries.values().map(|item| (item, depth + 1))); + } + _ => {} + } + } + Ok(keys) +} + +/// Python's `_token_reads` over `[A-Za-z_][\w$]*` tokens of ASCII text. +fn token_reads(sql: &str, keys: &[String]) -> Vec { + let bytes = sql.as_bytes(); + let mut tokens: Vec = Vec::new(); + let mut index = 0; + while index < bytes.len() { + if !(bytes[index].is_ascii_alphabetic() || bytes[index] == b'_') { + index += 1; + continue; + } + let start = index; + index += 1; + while index < bytes.len() + && (bytes[index].is_ascii_alphanumeric() || matches!(bytes[index], b'_' | b'$')) + { + index += 1; + } + let token = sql[start..index].to_ascii_lowercase(); + if !tokens.contains(&token) { + tokens.push(token); + } + } + tokens.retain(|token| keys.contains(token)); + tokens +} + +/// Python's `_read_helper_keys`: non-mock CTEs the test's readers reach. +fn read_helper_keys(graph: &CteGraph<'_>) -> Vec { + graph + .reachable(&graph.reader_reads) + .into_iter() + .filter(|key| graph.cte(key).is_some_and(|cte| !is_mock_name(&cte.name))) + .collect() +} + +/// Python's `_mock_keys`: the case-folded mock CTE names that stand in for `reference`. +fn mock_keys(reference: &Reference) -> Deferrable> { + let prefix = match reference.kind.as_str() { + "ref" => "__ref__", + "source" => "__source__", + "seed" => "__seed__", + "dbt_ref" => "__dbt_ref__", + "table_fn" => "__table_fn__", + _ => return Ok(Vec::new()), + }; + let mut names: Vec = vec![reference.name.clone()]; + if let Some(package) = &reference.package { + names.push(format!("{package}__{}", reference.name)); + } + names + .iter() + .map(|name| ascii_fold(&format!("{prefix}{name}"))) + .collect() +} + +/// Python's `_used_mock_keys`. +fn used_mock_keys( + request: &MockReadsRequest<'_>, + graph: &CteGraph<'_>, + called_mocks: &[String], +) -> Deferrable> { + let mock_model_names = &request.payload.mock_model_names; + let mut used: Vec = graph + .reachable(&graph.reader_reads) + .into_iter() + .filter(|key| graph.cte(key).is_some_and(|cte| is_mock_name(&cte.name))) + .collect(); + let mut seen_called: Vec<&String> = Vec::new(); + for key in called_mocks { + if seen_called.contains(&key) { + continue; + } + seen_called.push(key); + if graph.cte(key).is_some() && !used.contains(key) { + used.push(key.clone()); + } + } + let mut model_references: OrderedEntries<&[SqlTestAssemblyReference]> = OrderedEntries::new(); + for model in request.models { + model_references.assign(model.name.clone(), model.references.as_slice()); + } + let mut pending: Vec = request + .target_model_names + .iter() + .filter(|name| !mock_model_names.contains(name)) + .cloned() + .collect(); + let mut visited: HashSet = pending.iter().cloned().collect(); + let mut cursor = 0; + while cursor < pending.len() { + let model_name = pending[cursor].clone(); + cursor += 1; + let references: &[SqlTestAssemblyReference] = model_references + .get(&model_name) + .copied() + .unwrap_or_default(); + for reference in references { + let reference = model_reference(reference); + for mock_key in mock_keys(&reference)? { + if graph.cte(&mock_key).is_some() && !used.contains(&mock_key) { + used.push(mock_key); + } + } + if reference.kind == REF_KIND + && !mock_model_names.contains(&reference.name) + && visited.insert(reference.name.clone()) + { + pending.push(reference.name); + } + } + } + Ok(used) +} + +/// Python's `SqlReferenceKind.example_call(*args, quote='"')`. +fn example_call(kind: &str, arguments: &[&str]) -> String { + let quoted: Vec = arguments + .iter() + .map(|argument| format!("\"{}\"", argument.replace('"', "\"\""))) + .collect(); + format!("__{kind}({})", quoted.join(", ")) +} + +/// Python's `_reference_call`. +fn reference_call(reference: &Reference) -> String { + match (&reference.package, reference.kind.as_str()) { + (Some(package), DBT_REF_KIND) => example_call(&reference.kind, &[package, &reference.name]), + _ => example_call(&reference.kind, &[&reference.name]), + } +} + +/// Python's `_mock_reference_help`. +fn mock_reference_help(mock_name: &str, call: &str, reference: &Reference) -> String { + if reference.kind != TABLE_FUNCTION_KIND && reference.package.is_none() { + let mock_cte = format!("__{}__{}", reference.kind, reference.name); + return format!( + "Read a mock by its CTE name instead, for example FROM {mock_cte} rather than \ + FROM {call}, defining {mock_cte} AS (SELECT ...) if the test does not mock it, \ + or write the rows of '{mock_name}' directly." + ); + } + format!("Write the rows of '{mock_name}' directly, for example {mock_name} AS (SELECT ...).") +} + +/// Python's `sql_test_cte_location` and `reference_call_location` on ASCII contents. +fn located(test: &SqlTestAssemblyTest, cte_name: &str, call: &str) -> Span { + let contents = test.contents.as_str(); + let block_offset = contents.find(test.block_sql.as_str()).unwrap_or(0); + let (start, length) = match cte_header(contents, cte_name, block_offset) { + Some((header_start, header_end)) => find_ignoring_case(contents, call, header_end) + .map_or((header_start, cte_name.len()), |found| (found, call.len())), + None => (block_offset, 0), + }; + let (line, column) = line_and_column(contents, start); + let (end_line, end_column) = line_and_column(contents, start + length); + Span { + line, + column, + end_line, + end_column, + } +} + +/// Python's `(? Option<(usize, usize)> { + let bytes = contents.as_bytes(); + let mut start = from; + while let Some(found) = find_ignoring_case(contents, name, start) { + start = found + 1; + if found > 0 && is_word_or_dollar(bytes[found - 1]) { + continue; + } + let mut cursor = found + name.len(); + if matches!(bytes.get(cursor), Some(b'"' | b'`')) { + cursor += 1; + } + let spaces = cursor; + while bytes + .get(cursor) + .is_some_and(|byte| is_python_ascii_space(*byte)) + { + cursor += 1; + } + if cursor == spaces + || !bytes + .get(cursor..cursor + 2) + .is_some_and(|keyword| keyword.eq_ignore_ascii_case(b"AS")) + { + continue; + } + cursor += 2; + while bytes + .get(cursor) + .is_some_and(|byte| is_python_ascii_space(*byte)) + { + cursor += 1; + } + if bytes.get(cursor) == Some(&b'(') { + return Some((found, cursor + 1)); + } + } + None +} + +fn find_ignoring_case(contents: &str, needle: &str, from: usize) -> Option { + let haystack = contents.as_bytes(); + let needle = needle.as_bytes(); + if needle.is_empty() { + return (from <= haystack.len()).then_some(from); + } + (from..=haystack.len().checked_sub(needle.len())?) + .find(|&index| haystack[index..index + needle.len()].eq_ignore_ascii_case(needle)) +} + +fn is_word_or_dollar(byte: u8) -> bool { + byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'$') +} + +/// Python's `\s` on ASCII text, which includes the information separators. +fn is_python_ascii_space(byte: u8) -> bool { + matches!( + byte, + b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c | 0x1c..=0x1f + ) +} + +fn line_and_column(contents: &str, offset: usize) -> (usize, usize) { + let before = &contents.as_bytes()[..offset]; + let line = before.iter().filter(|byte| **byte == b'\n').count() + 1; + let line_start = before + .iter() + .rposition(|byte| *byte == b'\n') + .map_or(0, |index| index + 1); + (line, offset - line_start + 1) +} diff --git a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mod.rs b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mod.rs index 364bfe13c4..2661b0ec0a 100644 --- a/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mod.rs +++ b/crates/sqlbuild-analysis/src/compiler/_helpers/sql_tests/mod.rs @@ -1,4 +1,6 @@ +pub mod assembly; pub mod authored_macro_calls; +pub mod case_identity; pub mod cte_rename; pub mod cte_slices; pub mod cte_sql; @@ -7,7 +9,9 @@ pub mod extraction; pub mod glue; pub mod helper_names; pub mod helper_scope; +pub mod macro_call_names; pub mod markers; +pub mod mock_reads; pub mod planning; pub mod reader_references; pub mod reference_calls; diff --git a/crates/sqlbuild-analysis/src/compiler/main/mod.rs b/crates/sqlbuild-analysis/src/compiler/main/mod.rs index 357fadc9d0..94b6925b7e 100644 --- a/crates/sqlbuild-analysis/src/compiler/main/mod.rs +++ b/crates/sqlbuild-analysis/src/compiler/main/mod.rs @@ -1,4 +1,5 @@ pub mod sql_scenario_extraction; +pub mod sql_test_assembly; pub mod sql_test_chain_resolution; pub mod sql_test_chains; pub mod sql_test_difference_sampling; diff --git a/crates/sqlbuild-analysis/src/compiler/main/sql_test_assembly.rs b/crates/sqlbuild-analysis/src/compiler/main/sql_test_assembly.rs new file mode 100644 index 0000000000..f3af180469 --- /dev/null +++ b/crates/sqlbuild-analysis/src/compiler/main/sql_test_assembly.rs @@ -0,0 +1,9 @@ +//! Compiled SQL test facts from a typed request, test by test. + +use crate::compiler::_helpers::sql_tests::assembly; +use crate::compiler::models::{SqlTestAssemblyBatch, SqlTestAssemblyOutcome}; + +/// Assemble every test of `batch` in request order; a deferred test is Python's to assemble. +pub fn assemble_sql_test_batch(batch: &SqlTestAssemblyBatch) -> Vec { + assembly::assemble_batch(batch) +} diff --git a/crates/sqlbuild-analysis/src/compiler/models.rs b/crates/sqlbuild-analysis/src/compiler/models.rs index 03e40d082d..ca6719b481 100644 --- a/crates/sqlbuild-analysis/src/compiler/models.rs +++ b/crates/sqlbuild-analysis/src/compiler/models.rs @@ -182,3 +182,153 @@ pub struct SqlTestAssertionStep { #[serde(default)] pub comparison_body_sql: Option, } + +/// The compiled SQL tests to assemble, with the facts of every model the project compiles. +#[derive(Debug)] +pub struct SqlTestAssemblyBatch { + pub models: Vec, + pub tests: Vec, + pub lexical_syntax: LexicalSyntax, +} + +/// What assembly reads of one model: its name, macro dependencies and references. +#[derive(Debug)] +pub struct SqlTestAssemblyModel { + pub name: String, + pub macro_deps: Vec, + /// Pre-macro SQL Python scans for calls: set only without macro deps and with a macro token. + pub unscanned_macro_source: Option, + pub references: Vec, +} + +/// One logical reference: Python `SqlReferenceKind` value, name and optional package. +#[derive(Clone, Debug)] +pub struct SqlTestAssemblyReference { + pub kind: String, + pub name: String, + pub package: Option, +} + +/// One expanded SQL test case as compile inputs carry it. +#[derive(Debug)] +pub struct SqlTestAssemblyTest { + pub block_name: Option, + pub file_stem: String, + pub relative_path: String, + pub relative_stem: String, + pub contents: String, + pub block_sql: String, + pub block_index: i64, + pub sql_body: String, + pub case_name: Option, + /// `(name, value kind, nullable)` per declared parameter. + pub parameter_schema: Vec<(String, String, bool)>, + pub parameter_values: Vec<(String, SqlTestParameterValue)>, + pub payload: SqlTestAssemblyPayload, +} + +/// A typed SQL value as its kind and payload; decimals keep their unnormalized digits. +#[derive(Clone, Debug)] +pub enum SqlTestParameterValue { + String(String), + Integer(i64), + Boolean(bool), + Float(f64), + Decimal { + negative: bool, + digits: Vec, + exponent: i64, + }, + Null, + List(Vec), + Set(Vec), + Object(Vec<(String, SqlTestParameterValue)>), +} + +/// The part of a test's payload assembly reads. +#[derive(Debug)] +pub enum SqlTestAssemblyPayload { + /// A macro, UDF or table-function test of the named resources. + Direct { + mode: String, + tested_resource_names: Vec, + }, + Model(SqlTestAssemblyModelPayload), +} + +#[derive(Debug)] +pub struct SqlTestAssemblyModelPayload { + pub authored_ctes: Vec, + pub expected_ctes: Vec, + pub assertion_ctes: Vec, + pub expected_model_names: Vec, + pub assertion_target_model_names: Vec, + pub reference_target_model_names: Vec, + pub mock_model_names: Vec, + pub has_macro_mocks: bool, +} + +/// One test's assembled facts, or why Python assembles it. +#[derive(Debug, PartialEq)] +pub enum SqlTestAssemblyOutcome { + Assembled(AssembledSqlTestFacts), + Deferred(SqlTestAssemblyDeferral), +} + +/// The facts Python's `_assemble_compiled_sql_test` computes for one test. +#[derive(Debug, PartialEq)] +pub struct AssembledSqlTestFacts { + pub name: String, + /// `(resource type, name)` per scope dependency, in Python's order. + pub scope_deps: Vec<(&'static str, String)>, + pub target_model_names: Vec, + pub case_fingerprint: Option, + /// Resource name of the test's diagnostics: the block name, else the relative path's stem. + pub diagnostic_resource_name: String, + pub diagnostics: Vec, +} + +/// One P013 diagnostic for a mock that reads a helper calling a reference. +#[derive(Debug, PartialEq, Eq)] +pub struct SqlTestHelperDiagnostic { + pub line: usize, + pub column: usize, + pub end_line: usize, + pub end_column: usize, + pub message: String, + pub help: String, +} + +/// Why one test is assembled by Python instead. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SqlTestAssemblyDeferral { + /// Macro mocks re-expand every model, which only Python's macro expansion does. + MacroMocks, + /// A model's macro call scan raises in Python or meets text Python classifies by Unicode. + MacroCallScan, + /// The reference scan fails or cannot classify the text as Python does. + ReferenceScan, + /// Non-ASCII text where Python's case folding or Unicode classes would apply. + NonAsciiText, + /// A decimal parameter Python's decimal context would round or clamp. + DecimalContext, + /// A parameter value the JSON encoder cannot encode as Python's does. + UnencodableValue, + /// A parsed CTE tree too deep, or otherwise unfit, to read as Python's `to_dict` walk does. + UnreadableTree, +} + +impl SqlTestAssemblyDeferral { + /// The kind recorded for the deferral. + pub fn as_str(self) -> &'static str { + match self { + Self::MacroMocks => "macro_mocks", + Self::MacroCallScan => "macro_call_scan", + Self::ReferenceScan => "reference_scan", + Self::NonAsciiText => "non_ascii_text", + Self::DecimalContext => "decimal_context", + Self::UnencodableValue => "unencodable_value", + Self::UnreadableTree => "unreadable_tree", + } + } +} diff --git a/crates/sqlbuild-analysis/src/compiler/tests/test_sql_test_helper_references.rs b/crates/sqlbuild-analysis/src/compiler/tests/test_sql_test_helper_references.rs index a3b311b682..05d1594a41 100644 --- a/crates/sqlbuild-analysis/src/compiler/tests/test_sql_test_helper_references.rs +++ b/crates/sqlbuild-analysis/src/compiler/tests/test_sql_test_helper_references.rs @@ -1,11 +1,19 @@ use serde_json::{Value, json}; +use crate::compiler::_helpers::sql_tests::extraction::generic_syntax; +use crate::compiler::main::sql_test_assembly::assemble_sql_test_batch; +use crate::compiler::models::{ + AssembledSqlTestFacts, SqlTestAssemblyBatch, SqlTestAssemblyDeferral, SqlTestAssemblyModel, + SqlTestAssemblyModelPayload, SqlTestAssemblyOutcome, SqlTestAssemblyPayload, + SqlTestAssemblyReference, SqlTestAssemblyTest, SqlTestCte, SqlTestHelperDiagnostic, + SqlTestParameterValue, +}; use crate::compiler::tests::helpers::{ chain_helper_reference_case, defined_before, plan_helper_reference_case, plan_helper_reference_response, }; use crate::compiler::tests::test_types::{ - HelperReferenceTestCase, UnresolvedReaderReferenceTestCase, + HelperReferenceTestCase, SqlTestAssemblyTestCase, UnresolvedReaderReferenceTestCase, }; const HELPER_READS_MODEL: (&str, &str) = ( @@ -30,6 +38,14 @@ const ASSERT_DOUBLED: (&str, &str) = ( "SELECT order_id FROM doubled WHERE amount_doubled <> 20", ); +const MOCK_READS_HELPER_TEST: &str = "TEST (name \"mock_reads_helper\");\n\nWITH\n\ +orders_feed AS (SELECT * FROM __source(\"raw_orders\")),\n\ +__ref__stg_orders AS (SELECT * FROM orders_feed),\n\ +__expected__customer_totals AS (SELECT 1 AS customer_id)\nSELECT 1\n"; +/// Python's `build_sql_test_case_fingerprint` of the parameterized case below. +const PYTHON_CASE_FINGERPRINT: &str = + "8f2adcab557ba4476fcb70de1fc11014acda9f1b597a3ca5c3245afb632e5d0f"; + #[test] fn given_helper_cte_references_when_planning_then_references_resolve_in_dependency_order() { let test_cases = [ @@ -491,3 +507,201 @@ fn given_unresolvable_reader_references_when_planning_directly_then_planner_reje ); } } + +#[test] +fn given_compiled_sql_test_inputs_when_assembling_then_facts_match_python_or_defer() { + let cte = |name: &str, sql_body: &str| SqlTestCte { + name: name.to_owned(), + sql_body: sql_body.to_owned(), + }; + let strings = + |names: &[&str]| -> Vec { names.iter().map(|n| (*n).to_owned()).collect() }; + let model_test = |contents: &str, has_macro_mocks: bool| SqlTestAssemblyTest { + block_name: Some("mock_reads_helper".to_owned()), + file_stem: "test_customer_totals".to_owned(), + relative_path: "tests/unit/test_customer_totals.sql".to_owned(), + relative_stem: "test_customer_totals".to_owned(), + contents: contents.to_owned(), + block_sql: contents + .split_once("\n\n") + .map_or("", |(_, body)| body) + .to_owned(), + block_index: 1, + sql_body: "SELECT 1".to_owned(), + case_name: None, + parameter_schema: Vec::new(), + parameter_values: Vec::new(), + payload: SqlTestAssemblyPayload::Model(SqlTestAssemblyModelPayload { + authored_ctes: vec![ + cte("orders_feed", "SELECT * FROM __source(\"raw_orders\")"), + cte("__ref__stg_orders", "SELECT * FROM orders_feed"), + ], + expected_ctes: vec![cte( + "__expected__customer_totals", + "SELECT 1 AS customer_id", + )], + assertion_ctes: Vec::new(), + expected_model_names: strings(&["customer_totals"]), + assertion_target_model_names: Vec::new(), + reference_target_model_names: Vec::new(), + mock_model_names: strings(&["stg_orders"]), + has_macro_mocks, + }), + }; + let model = |name: &str, macro_deps: &[&str], source: Option<&str>, refs: &[(&str, &str)]| { + SqlTestAssemblyModel { + name: name.to_owned(), + macro_deps: strings(macro_deps), + unscanned_macro_source: source.map(str::to_owned), + references: refs + .iter() + .map(|(kind, name)| SqlTestAssemblyReference { + kind: (*kind).to_owned(), + name: (*name).to_owned(), + package: None, + }) + .collect(), + } + }; + let models = || { + vec![ + model("stg_orders", &[], None, &[("source", "raw_orders")]), + model("customer_totals", &[], None, &[("ref", "stg_orders")]), + model( + "order_cents", + &[], + Some("SELECT @enum(\"order_channel\").WEB, @@scale * @ cents(amount) FROM t"), + &[], + ), + model( + "order_dollars", + &[], + Some("SELECT '@cents(x)', @dollars (amount)"), + &[], + ), + ] + }; + let batch = |tests: Vec| SqlTestAssemblyBatch { + models: models(), + tests, + lexical_syntax: generic_syntax(), + }; + let macro_test = SqlTestAssemblyTest { + block_name: None, + payload: SqlTestAssemblyPayload::Direct { + mode: "macro".to_owned(), + tested_resource_names: strings(&["dollars"]), + }, + ..model_test(MOCK_READS_HELPER_TEST, false) + }; + let case_test = |decimal_digits: Vec| SqlTestAssemblyTest { + relative_path: "tests/unit/test_cases.sql".to_owned(), + case_name: Some("first".to_owned()), + parameter_schema: vec![ + ("p_decimal".to_owned(), "decimal".to_owned(), true), + ("p_float".to_owned(), "float".to_owned(), false), + ], + parameter_values: vec![ + ( + "p_decimal".to_owned(), + SqlTestParameterValue::Decimal { + negative: true, + digits: decimal_digits, + exponent: -4, + }, + ), + ("p_float".to_owned(), SqlTestParameterValue::Float(0.1)), + ( + "p_string".to_owned(), + SqlTestParameterValue::String("caf\u{e9}".to_owned()), + ), + ], + payload: SqlTestAssemblyPayload::Model(SqlTestAssemblyModelPayload { + authored_ctes: Vec::new(), + expected_ctes: Vec::new(), + assertion_ctes: Vec::new(), + expected_model_names: strings(&["orders", "customers"]), + assertion_target_model_names: strings(&["orders"]), + reference_target_model_names: Vec::new(), + mock_model_names: Vec::new(), + has_macro_mocks: false, + }), + ..model_test(MOCK_READS_HELPER_TEST, false) + }; + let test_cases = [ + SqlTestAssemblyTestCase { + description: "a mock reading a helper that calls a source reports P013 at the call", + batch: batch(vec![model_test(MOCK_READS_HELPER_TEST, false)]), + expected_outcomes: vec![SqlTestAssemblyOutcome::Assembled(AssembledSqlTestFacts { + name: "mock_reads_helper".to_owned(), + scope_deps: vec![("model", "customer_totals".to_owned())], + target_model_names: strings(&["customer_totals"]), + case_fingerprint: None, + diagnostic_resource_name: "mock_reads_helper".to_owned(), + diagnostics: vec![SqlTestHelperDiagnostic { + line: 4, + column: 31, + end_line: 4, + end_column: 53, + message: "SQL test mock '__ref__stg_orders' reads helper CTE 'orders_feed', \ + which calls __source(\"raw_orders\"); mocks and fixtures are \ + defined before the models the test runs, so the helper cannot \ + be resolved for them" + .to_owned(), + help: "Read a mock by its CTE name instead, for example FROM \ + __source__raw_orders rather than FROM __source(\"raw_orders\"), \ + defining __source__raw_orders AS (SELECT ...) if the test does not \ + mock it, or write the rows of '__ref__stg_orders' directly." + .to_owned(), + }], + })], + }, + SqlTestAssemblyTestCase { + description: "macro mocks, non-ASCII text and out-of-context decimals defer", + batch: batch(vec![ + model_test(MOCK_READS_HELPER_TEST, true), + model_test(&format!("-- caf\u{e9}\n{MOCK_READS_HELPER_TEST}"), false), + case_test(vec![1; 29]), + ]), + expected_outcomes: vec![ + SqlTestAssemblyOutcome::Deferred(SqlTestAssemblyDeferral::MacroMocks), + SqlTestAssemblyOutcome::Deferred(SqlTestAssemblyDeferral::NonAsciiText), + SqlTestAssemblyOutcome::Deferred(SqlTestAssemblyDeferral::DecimalContext), + ], + }, + SqlTestAssemblyTestCase { + description: "a case fingerprint and a macro test's scanned scope match Python", + batch: batch(vec![case_test(vec![2, 4, 7, 0, 0]), macro_test]), + expected_outcomes: vec![ + SqlTestAssemblyOutcome::Assembled(AssembledSqlTestFacts { + name: "mock_reads_helper [first]".to_owned(), + scope_deps: vec![ + ("model", "orders".to_owned()), + ("model", "customers".to_owned()), + ], + target_model_names: strings(&["orders", "customers"]), + case_fingerprint: Some(PYTHON_CASE_FINGERPRINT.to_owned()), + diagnostic_resource_name: "mock_reads_helper".to_owned(), + diagnostics: Vec::new(), + }), + SqlTestAssemblyOutcome::Assembled(AssembledSqlTestFacts { + name: "test_customer_totals".to_owned(), + scope_deps: vec![("model", "order_dollars".to_owned())], + target_model_names: Vec::new(), + case_fingerprint: None, + diagnostic_resource_name: "test_customer_totals".to_owned(), + diagnostics: Vec::new(), + }), + ], + }, + ]; + + for test_case in test_cases { + assert_eq!( + assemble_sql_test_batch(&test_case.batch), + test_case.expected_outcomes, + "{}", + test_case.description + ); + } +} diff --git a/crates/sqlbuild-analysis/src/compiler/tests/test_types.rs b/crates/sqlbuild-analysis/src/compiler/tests/test_types.rs index c109a747fb..3d59ff16d4 100644 --- a/crates/sqlbuild-analysis/src/compiler/tests/test_types.rs +++ b/crates/sqlbuild-analysis/src/compiler/tests/test_types.rs @@ -186,3 +186,9 @@ pub(crate) struct GlueErrorProjectionTestCase { pub(crate) warnings: &'static [(&'static str, &'static str)], pub(crate) expected_messages: &'static [&'static str], } + +pub(crate) struct SqlTestAssemblyTestCase { + pub(crate) description: &'static str, + pub(crate) batch: crate::compiler::models::SqlTestAssemblyBatch, + pub(crate) expected_outcomes: Vec, +} diff --git a/crates/sqlbuild-analysis/src/contracts/_helpers/columns.rs b/crates/sqlbuild-analysis/src/contracts/_helpers/columns.rs index 7e7fda68b8..20922fe52b 100644 --- a/crates/sqlbuild-analysis/src/contracts/_helpers/columns.rs +++ b/crates/sqlbuild-analysis/src/contracts/_helpers/columns.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use crate::contracts::_helpers::dynamic::dynamic_column_diagnostics; -use crate::contracts::_helpers::type_comparison::{TypeComparison, types_equal}; +use crate::contracts::_helpers::type_comparison::{TypeComparer, TypeComparison}; use crate::contracts::constants::{ CONTRACT_ENFORCED, CONTRACT_NONE, DYNAMIC_OUTPUT_NOT_PROVEN_CODE, EXTRA_COLUMN_CODE, EXTRA_COLUMN_HELP, EXTRA_COLUMN_NAMED_SCHEMA_HELP, MISSING_COLUMN_CODE, @@ -45,7 +45,7 @@ pub(crate) fn declared_shape_validation_is_active(model: &ContractModel, implici pub(crate) fn model_contract_diagnostics( model: &ContractModel, validate_declared_shape: bool, - dialect: &str, + types: &TypeComparer<'_>, ) -> Result, ContractDeferral> { let contract_enforced: bool = model.contract.as_deref() == Some(CONTRACT_ENFORCED); let Some(schema) = model @@ -59,7 +59,7 @@ pub(crate) fn model_contract_diagnostics( Vec::new() }); }; - let mut diagnostics: Vec = dynamic_column_diagnostics(model, dialect)?; + let mut diagnostics: Vec = dynamic_column_diagnostics(model, types)?; let dynamic_output_unproven: bool = diagnostics .iter() .any(|diagnostic| diagnostic.code == DYNAMIC_OUTPUT_NOT_PROVEN_CODE); @@ -107,7 +107,7 @@ pub(crate) fn model_contract_diagnostics( type_enforcement: schema.type_enforcement, contract_enforced, unchecked: &unchecked, - dialect, + types, }; diagnostics.extend(column_type(&checked, &check)?); } @@ -118,7 +118,7 @@ struct TypeCheck<'a> { type_enforcement: bool, contract_enforced: bool, unchecked: &'a HashSet<&'a str>, - dialect: &'a str, + types: &'a TypeComparer<'a>, } struct TypedColumn<'a> { @@ -271,7 +271,7 @@ fn column_type( help: UNKNOWN_TYPE_HELP.to_owned(), })); }; - if types_equal(declared_type, inferred_type, check.dialect)? == TypeComparison::Equal { + if check.types.types_equal(declared_type, inferred_type)? == TypeComparison::Equal { return Ok(None); } Ok(Some(ContractDiagnostic { diff --git a/crates/sqlbuild-analysis/src/contracts/_helpers/dynamic.rs b/crates/sqlbuild-analysis/src/contracts/_helpers/dynamic.rs index b42f5df666..058b485381 100644 --- a/crates/sqlbuild-analysis/src/contracts/_helpers/dynamic.rs +++ b/crates/sqlbuild-analysis/src/contracts/_helpers/dynamic.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; -use crate::contracts::_helpers::type_comparison::{TypeComparison, types_equal}; +use crate::contracts::_helpers::type_comparison::{TypeComparer, TypeComparison}; use crate::contracts::constants::{ DYNAMIC_FAMILY_TYPE_MISMATCH_HELP, DYNAMIC_FAMILY_UNKNOWN_TYPE_HELP, DYNAMIC_OUTPUT_NOT_PROVEN_CODE, DYNAMIC_OUTPUT_NOT_PROVEN_HELP, NO_COMPILER_EVIDENCE, @@ -16,7 +16,7 @@ use crate::contracts::models::{ /// The dynamic column contract diagnostics of one model, before its fixed columns. pub(crate) fn dynamic_column_diagnostics( model: &ContractModel, - dialect: &str, + types: &TypeComparer<'_>, ) -> Result, ContractDeferral> { let Some(schema) = model .schema @@ -49,7 +49,7 @@ pub(crate) fn dynamic_column_diagnostics( )); continue; }; - if types_equal(declared, inferred, dialect)? == TypeComparison::Different { + if types.types_equal(declared, inferred)? == TypeComparison::Different { diagnostics.push(family_diagnostic( TYPE_MISMATCH_CODE, ContractSeverity::Error, diff --git a/crates/sqlbuild-analysis/src/contracts/_helpers/type_comparison.rs b/crates/sqlbuild-analysis/src/contracts/_helpers/type_comparison.rs index 9089685e7e..13bb94ae69 100644 --- a/crates/sqlbuild-analysis/src/contracts/_helpers/type_comparison.rs +++ b/crates/sqlbuild-analysis/src/contracts/_helpers/type_comparison.rs @@ -1,5 +1,8 @@ //! Python's `types_equal` over the native type system, deferring where it cannot answer. +use std::cell::RefCell; +use std::collections::HashMap; + use crate::contracts::models::ContractDeferral; use crate::type_system::main::normalize_type::normalize_type; use crate::type_system::models::{NormalizedType, TypeNormalization}; @@ -11,23 +14,44 @@ pub(crate) enum TypeComparison { Different, } -/// Compare two types as Python's `types_equal`, or defer when either type has no native answer. -pub(crate) fn types_equal( - left: &str, - right: &str, - dialect: &str, -) -> Result { - let left: NormalizedType = normalized(left, dialect)?; - let right: NormalizedType = normalized(right, dialect)?; - Ok(if left == right { - TypeComparison::Equal - } else { - TypeComparison::Different - }) +/// One request's type comparisons, normalizing each type string once as Python's cache does. +pub(crate) struct TypeComparer<'a> { + dialect: &'a str, + normalized: RefCell>>, } -fn normalized(type_sql: &str, dialect: &str) -> Result { - normalize_type(type_sql, dialect) - .map(|TypeNormalization { normalized, .. }| normalized) - .ok_or(ContractDeferral::TypeNormalization) +impl<'a> TypeComparer<'a> { + pub(crate) fn new(dialect: &'a str) -> Self { + Self { + dialect, + normalized: RefCell::new(HashMap::new()), + } + } + + /// Compare two types as Python's `types_equal`, or defer when either has no native answer. + pub(crate) fn types_equal( + &self, + left: &str, + right: &str, + ) -> Result { + let left: NormalizedType = self.normalized(left)?; + let right: NormalizedType = self.normalized(right)?; + Ok(if left == right { + TypeComparison::Equal + } else { + TypeComparison::Different + }) + } + + fn normalized(&self, type_sql: &str) -> Result { + if let Some(known) = self.normalized.borrow().get(type_sql) { + return known.clone().ok_or(ContractDeferral::TypeNormalization); + } + let normalized: Option = normalize_type(type_sql, self.dialect) + .map(|TypeNormalization { normalized, .. }| normalized); + self.normalized + .borrow_mut() + .insert(type_sql.to_owned(), normalized.clone()); + normalized.ok_or(ContractDeferral::TypeNormalization) + } } diff --git a/crates/sqlbuild-analysis/src/contracts/main/evaluate_model_contracts.rs b/crates/sqlbuild-analysis/src/contracts/main/evaluate_model_contracts.rs index b70090de85..a1fa939fbf 100644 --- a/crates/sqlbuild-analysis/src/contracts/main/evaluate_model_contracts.rs +++ b/crates/sqlbuild-analysis/src/contracts/main/evaluate_model_contracts.rs @@ -3,12 +3,14 @@ use crate::contracts::_helpers::columns::{ declared_shape_validation_is_active, model_contract_diagnostics, requires_contract_evaluation, }; +use crate::contracts::_helpers::type_comparison::TypeComparer; use crate::contracts::models::{ContractOutcome, ContractRequest}; /// One outcome per requested model; models that need no evaluation have no diagnostics. #[must_use] pub fn evaluate_model_contracts(request: &ContractRequest) -> Vec { let implicit: bool = request.implicit_column_contracts; + let types = TypeComparer::new(&request.dialect); request .models .iter() @@ -19,7 +21,7 @@ pub fn evaluate_model_contracts(request: &ContractRequest) -> Vec ContractOutcome::Diagnostics(diagnostics), Err(deferral) => ContractOutcome::Deferred(deferral), diff --git a/crates/sqlbuild-analysis/src/contracts/tests/test_evaluate_model_contracts.rs b/crates/sqlbuild-analysis/src/contracts/tests/test_evaluate_model_contracts.rs index fa83f9ded2..2b3883d3e1 100644 --- a/crates/sqlbuild-analysis/src/contracts/tests/test_evaluate_model_contracts.rs +++ b/crates/sqlbuild-analysis/src/contracts/tests/test_evaluate_model_contracts.rs @@ -1,9 +1,9 @@ use crate::contracts::main::evaluate_model_contracts::evaluate_model_contracts; -use crate::contracts::models::{ContractOutcome, ContractRequest}; +use crate::contracts::models::{ContractModel, ContractOutcome, ContractRequest}; use crate::contracts::tests::helpers::{ declared, dynamic_model, inferred, model, outcome_lines, proof, schema, with_inferred, }; -use crate::contracts::tests::test_types::ContractTestCase; +use crate::contracts::tests::test_types::{ContractTestCase, SharedTypesTestCase}; #[test] fn given_model_contracts_when_evaluating_then_diagnostics_follow_python_order() { @@ -210,3 +210,60 @@ fn given_model_contracts_when_evaluating_then_diagnostics_follow_python_order() ); } } + +#[test] +fn given_models_sharing_types_when_evaluating_together_then_each_matches_its_own_request() { + let enforced = |declared_type: &str, inferred_type: &str| { + with_inferred( + model( + Some("enforced"), + Some(schema( + vec![declared("amount", Some(declared_type), false)], + false, + )), + ), + vec![inferred("amount", Some(inferred_type), false)], + ) + }; + let test_cases = [SharedTypesTestCase { + description: "repeated equal, mismatched and unanswerable types", + models: vec![ + enforced("INT", "INTEGER"), + enforced("INT", "VARCHAR"), + enforced("TÉXT", "VARCHAR"), + enforced("INT", "INTEGER"), + enforced("INT", "VARCHAR"), + enforced("TÉXT", "VARCHAR"), + ], + expected_lines: &[ + "K002 error declared:0 column 'amount' inferred as VARCHAR but declared type is INT [amount: inferred VARCHAR]", + "deferred:type_normalization", + "K002 error declared:0 column 'amount' inferred as VARCHAR but declared type is INT [amount: inferred VARCHAR]", + "deferred:type_normalization", + ], + }]; + for test_case in test_cases { + let request = |models: Vec| ContractRequest { + dialect: "duckdb".to_owned(), + implicit_column_contracts: true, + models, + }; + let together: Vec = evaluate_model_contracts(&request(test_case.models.clone())) + .iter() + .flat_map(outcome_lines) + .collect(); + let alone: Vec = test_case + .models + .iter() + .flat_map(|model| evaluate_model_contracts(&request(vec![model.clone()]))) + .flat_map(|outcome| outcome_lines(&outcome)) + .collect(); + + assert_eq!(together, alone, "{}", test_case.description); + assert_eq!( + together, test_case.expected_lines, + "{}", + test_case.description + ); + } +} diff --git a/crates/sqlbuild-analysis/src/contracts/tests/test_types.rs b/crates/sqlbuild-analysis/src/contracts/tests/test_types.rs index bfbdb73893..43a0260eb6 100644 --- a/crates/sqlbuild-analysis/src/contracts/tests/test_types.rs +++ b/crates/sqlbuild-analysis/src/contracts/tests/test_types.rs @@ -8,6 +8,13 @@ pub(crate) struct ContractTestCase { pub(crate) expected_lines: &'static [&'static str], } +pub(crate) struct SharedTypesTestCase { + pub(crate) description: &'static str, + pub(crate) models: Vec, + /// Every model's lines in order, as each model's own single-model request yields them. + pub(crate) expected_lines: &'static [&'static str], +} + pub(crate) struct PromotionTestCase { pub(crate) description: &'static str, pub(crate) request: PromotionRequest, diff --git a/crates/sqlbuild-analysis/src/type_system/_helpers/parsed.rs b/crates/sqlbuild-analysis/src/type_system/_helpers/parsed.rs index dfc944b99f..dc08a3b5d3 100644 --- a/crates/sqlbuild-analysis/src/type_system/_helpers/parsed.rs +++ b/crates/sqlbuild-analysis/src/type_system/_helpers/parsed.rs @@ -227,8 +227,11 @@ fn python_str(value: &Value) -> Option { } } -/// Whether the wheel hands Python this value as an expression object rather than data. +/// Whether the wheel hands Python an expression object; every variant holds data, so not a scalar. fn is_python_expression(value: &Value) -> bool { + if !matches!(value, Value::Object(_) | Value::Array(_)) { + return false; + } if let Ok(_expression) = expression_from_value(value.clone()) { return true; } diff --git a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/mod.rs b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/mod.rs index 54e3fdf710..feba290be6 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/mod.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/mod.rs @@ -1,2 +1,3 @@ +pub(crate) mod oracle; pub(crate) mod registration; pub(crate) mod session; diff --git a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/oracle.rs b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/oracle.rs new file mode 100644 index 0000000000..e631bc54ea --- /dev/null +++ b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/oracle.rs @@ -0,0 +1,62 @@ +//! Test-only hook comparing native CTE fact recovery with Python's, function for function. + +use pyo3::prelude::{Bound, PyModule, PyModuleMethods, PyResult, Python}; +use pyo3::{pyfunction, wrap_pyfunction}; +use sqlbuild_analysis::assembly::analysis_session::main::recover_cte_facts::recover_cte_facts; +use sqlbuild_analysis::assembly::analysis_session::models::{CteFactRequest, CteFacts}; +use sqlbuild_analysis::assembly::analysis_session::types::{Pairs, Shapes}; + +use crate::bindings::_helpers::boundary::panics::value_error; +use crate::bindings::types::CompilerDetach; + +/// `(cleaned SQL, dialect, input schemas, return types, nullability rules, recover, null filter)`. +type RecoveryRow = (String, String, Shapes, Pairs, Option, bool, bool); +/// `(deferral, types, nullability, sorted direct outputs, sorted non-null outputs)`. +type FactsRow = (Option, Pairs, Pairs, Vec, Vec); + +/// The facts native enrichment recovers for one query, or the reason it defers to Python. +#[pyfunction] +fn _oracle_cte_fact_recovery(py: Python<'_>, request: RecoveryRow) -> PyResult { + let ( + cleaned_sql, + dialect, + input_schemas, + function_return_types, + nullability_rules, + recover, + null_filter, + ) = request; + let request = CteFactRequest { + cleaned_sql, + dialect, + input_schemas, + function_return_types, + nullability_rules, + recover, + null_filter, + }; + let facts: Result = py + .compiler_detach(|| Ok(recover_cte_facts(&request))) + .map_err(value_error)?; + Ok(match facts { + Ok(facts) => ( + None, + facts.types, + facts.nullability, + facts.direct_outputs, + facts.non_null_outputs, + ), + Err(deferral) => ( + Some(deferral), + Vec::new(), + Vec::new(), + Vec::new(), + Vec::new(), + ), + }) +} + +pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { + module.add_function(wrap_pyfunction!(_oracle_cte_fact_recovery, module)?)?; + Ok(()) +} diff --git a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/registration.rs b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/registration.rs index bfe82cb5d1..426d0f43eb 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/registration.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/registration.rs @@ -2,8 +2,9 @@ use pyo3::prelude::{Bound, PyModule, PyResult}; -use crate::bindings::_helpers::analysis_session::session; +use crate::bindings::_helpers::analysis_session::{oracle, session}; pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { - session::register(module) + session::register(module)?; + oracle::register(module) } diff --git a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/session.rs b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/session.rs index 87af8f9b33..5600b3448c 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/session.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/analysis_session/session.rs @@ -4,14 +4,18 @@ use pyo3::prelude::{Bound, PyModule, PyModuleMethods, PyRef, PyResult, Python}; use pyo3::{pyclass, pyfunction, pymethods, wrap_pyfunction}; use sqlbuild_analysis::assembly::analysis_session::main::expression_shapes::expression_shapes; use sqlbuild_analysis::assembly::analysis_session::main::finish_analysis_session::finish_analysis_session; -use sqlbuild_analysis::assembly::analysis_session::main::prove_dynamic_contract::prove_dynamic_contract; +use sqlbuild_analysis::assembly::analysis_session::main::finished_fact_models::finished_fact_models; +use sqlbuild_analysis::assembly::analysis_session::main::prove_dynamic_contracts::prove_dynamic_contracts; +use sqlbuild_analysis::assembly::analysis_session::main::prove_finished_dynamic_contracts::prove_finished_dynamic_contracts; use sqlbuild_analysis::assembly::analysis_session::main::provide_deferred_analyses::provide_deferred_analyses; use sqlbuild_analysis::assembly::analysis_session::main::run_analysis_session::run_analysis_session; +use sqlbuild_analysis::assembly::analysis_session::main::session_sharing::session_sharing; use sqlbuild_analysis::assembly::analysis_session::main::start_analysis_session::start_analysis_session; use sqlbuild_analysis::assembly::analysis_session::models::{ AnalysisSession, ColumnFact, Deferral, DeferredAnalysis, DynamicFamily, ExpressionShape, - ExpressionShapeRequest, LineageFacts, LineageRow, ModelOutcome, ModelReference, ModelRequest, - PivotOutcome, PivotRequest, SessionOutcome, SessionRequest, SessionStep, + ExpressionShapeRequest, FinishedSession, LineageFacts, LineageRow, ModelOutcome, + ModelReference, ModelRequest, PivotBatchRequest, PivotModel, PivotOutcome, PivotTables, + SessionOutcome, SessionRequest, SessionStep, }; use sqlbuild_analysis::assembly::analysis_session::types::{Pairs, Shapes}; use sqlbuild_analysis::semantic_validation::types::DiagnosticRow; @@ -47,6 +51,7 @@ type RequestRow = ( String, bool, Pairs, + Option, bool, Shapes, Shapes, @@ -97,15 +102,16 @@ type ProofRow = ( Option, bool, ); -/// The dialect, relation facts, families by table, SQL and families of one pivot proof. +/// One model's pivot SQL and declared families. +type PivotModelRow = (String, Vec); +/// The dialect, relation facts and families by table every proof reads, and the models. type PivotRequestRow = ( String, Shapes, Shapes, Shapes, Vec<(String, Vec)>, - String, - Vec, + Vec, ); /// `("absent" | "deferred" | "proof", proof)`. type ContractRow = (&'static str, Option); @@ -116,10 +122,17 @@ type FinishRow = (Vec, Shapes, Vec, Vec); #[pyclass(module = "sqlbuild._native")] pub(crate) struct NativeModelAnalysisSession { inner: Option, + finished: Option, failure: Option, + sharing: (usize, usize), } impl NativeModelAnalysisSession { + /// The finished session later compile stages read, once `finish` has succeeded. + pub(crate) fn finished_session(&self) -> Option<&FinishedSession> { + self.finished.as_ref() + } + /// Keep `result`'s value, or end the session and keep its failure for Python's debug log. fn kept(&mut self, result: Result) -> Option { match result { @@ -135,6 +148,15 @@ impl NativeModelAnalysisSession { #[pymethods] impl NativeModelAnalysisSession { + /// Models whose output names and lineage the finished session keeps for later stages. + #[getter] + fn fact_models(&self) -> Vec { + self.finished + .as_ref() + .map(finished_fact_models) + .unwrap_or_default() + } + /// Advance; None means Python must analyse every model, no deferrals means done. fn run(&mut self, py: Python<'_>) -> Option { let mut session: AnalysisSession = self.inner.take()?; @@ -143,6 +165,7 @@ impl NativeModelAnalysisSession { run_analysis_session(&mut session).map(|step| (session, step)) }); let (session, step) = self.kept(result)?; + self.sharing = session_sharing(&session); self.inner = Some(session); Some(step_row(step)) } @@ -162,9 +185,24 @@ impl NativeModelAnalysisSession { /// Every model's outcome once the session is done, or None to analyse in Python. fn finish(&mut self) -> Option { let session: AnalysisSession = self.inner.take()?; - let outcome: Result = - catch_compiler_panic(|| finish_analysis_session(session).map(finish_row)); - self.kept(outcome) + let outcome = catch_compiler_panic(|| finish_analysis_session(session)); + let (outcome, finished) = self.kept(outcome)?; + self.finished = Some(finished); + Some(finish_row(outcome)) + } + + /// Each model's dynamic pivot proof from the finished session's tables, or None for Python. + fn prove_dynamic_contracts( + &self, + py: Python<'_>, + models: Vec, + ) -> Option> { + let session: &FinishedSession = self.finished.as_ref()?; + let models: Vec = models.into_iter().map(pivot_model).collect(); + match py.compiler_detach(|| prove_finished_dynamic_contracts(session, &models)) { + Ok(outcomes) => Some(outcomes.into_iter().map(contract_row).collect()), + Err(_) => None, + } } /// Why the session handed the analysis back to Python, when it did. @@ -172,6 +210,12 @@ impl NativeModelAnalysisSession { fn failure(&self) -> Option { self.failure.clone() } + + /// `(shared members, shared members re-analysed alone)` as of the last step. + #[getter] + fn sharing(&self) -> (usize, usize) { + self.sharing + } } /// Start a session on `catalog`, or None where Python must analyse. @@ -188,7 +232,9 @@ fn start_model_analysis_session( .map_err(compiler_error)?; Ok(session.map(|session| NativeModelAnalysisSession { inner: Some(session), + finished: None, failure: None, + sharing: (0, 0), })) } @@ -226,6 +272,7 @@ fn session_request(request: RequestRow) -> SessionRequest { dialect, case_sensitive_shapes, function_return_types, + nullability_rules, rich_type_inference, column_types, column_nullability, @@ -238,6 +285,7 @@ fn session_request(request: RequestRow) -> SessionRequest { dialect, case_sensitive_shapes, function_return_types, + nullability_rules, rich_type_inference, column_types, column_nullability, @@ -425,28 +473,42 @@ fn outcome_row(outcome: ModelOutcome) -> OutcomeRow { ) } -/// One model's dynamic pivot proof, or `("deferred", None)` for Python's proof. +/// Each model's dynamic pivot proof outside any session, or None for Python's proofs. #[pyfunction] -fn prove_dynamic_column_contract(py: Python<'_>, request: PivotRequestRow) -> ContractRow { - let (dialect, column_types, authoritative_types, column_nullability, by_table, sql, families) = +fn prove_dynamic_column_contracts( + py: Python<'_>, + request: PivotRequestRow, +) -> Option> { + let (dialect, column_types, authoritative_types, column_nullability, by_table, models) = request; - let request = PivotRequest { - dialect, - column_types, - authoritative_types, - column_nullability, - families_by_table: families_by_table(by_table), + let request = PivotBatchRequest { + tables: PivotTables { + dialect, + column_types, + authoritative_types, + column_nullability, + families_by_table: families_by_table(by_table), + }, + models: models.into_iter().map(pivot_model).collect(), + }; + match py.compiler_detach(|| prove_dynamic_contracts(&request)) { + Ok(outcomes) => Some(outcomes.into_iter().map(contract_row).collect()), + Err(_) => None, + } +} + +fn pivot_model(row: PivotModelRow) -> PivotModel { + let (sql, families) = row; + PivotModel { sql, families: families.into_iter().map(dynamic_family).collect(), - }; - py.compiler_detach(|| prove_dynamic_contract(&request)) - .map_or(("deferred", None), contract_row) + } } pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { module.add_class::()?; module.add_function(wrap_pyfunction!(start_model_analysis_session, module)?)?; module.add_function(wrap_pyfunction!(infer_expression_source_shapes, module)?)?; - module.add_function(wrap_pyfunction!(prove_dynamic_column_contract, module)?)?; + module.add_function(wrap_pyfunction!(prove_dynamic_column_contracts, module)?)?; Ok(()) } diff --git a/crates/sqlbuild-python/src/bindings/_helpers/project_assembly/resources.rs b/crates/sqlbuild-python/src/bindings/_helpers/project_assembly/resources.rs index d2fbcc1350..48d24695f1 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/project_assembly/resources.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/project_assembly/resources.rs @@ -4,6 +4,7 @@ use pyo3::prelude::{Bound, PyModule, PyModuleMethods, PyResult, Python}; use pyo3::{pyfunction, wrap_pyfunction}; use sqlbuild_analysis::assembly::analysis_session::types::Pairs; use sqlbuild_analysis::assembly::project::main::assemble_project_resources::assemble_project_resources; +use sqlbuild_analysis::assembly::project::main::check_sql_syntax::check_sql_syntax; use sqlbuild_analysis::assembly::project::models::{ AuditFacts, InputRead, ModelFacts, Namespace, ProjectRequest, ProjectResources, Reference, SeedDefaults, SeedFacts, SourceFacts, SyntaxCheck, TargetNamespace, Variable, @@ -84,6 +85,23 @@ fn assemble_project_resource_facts( } } +/// Whether every `(sql, placeholders)` parses, or None with the reason Python must check it. +#[pyfunction] +fn check_native_sql_syntax( + py: Python<'_>, + request: (String, Vec<(String, Pairs)>), +) -> (Option, Option) { + let (dialect, rows) = request; + let checks: Vec = rows + .into_iter() + .map(|(sql, placeholders)| SyntaxCheck { sql, placeholders }) + .collect(); + match py.compiler_detach(|| check_sql_syntax(&dialect, &checks)) { + Ok(valid) => (Some(valid), None), + Err(reason) => (None, Some(reason)), + } +} + fn project_request(request: RequestRow) -> ProjectRequest { let ( dialect, @@ -203,5 +221,6 @@ fn namespace_row(namespace: Namespace) -> NamespaceRow { pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { module.add_function(wrap_pyfunction!(assemble_project_resource_facts, module)?)?; + module.add_function(wrap_pyfunction!(check_native_sql_syntax, module)?)?; Ok(()) } diff --git a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/completion.rs b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/completion.rs index c9ac573eaa..c01e4e67d9 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/completion.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/completion.rs @@ -8,7 +8,9 @@ use sqlbuild_analysis::semantic_checks::models::{ SemanticLocation, }; +use crate::bindings::_helpers::analysis_session::session::NativeModelAnalysisSession; use crate::bindings::_helpers::boundary::panics::compiler_error; +use crate::bindings::_helpers::semantic_checks::session_facts::session_model_facts; use crate::bindings::_helpers::semantic_checks::type_recovery::{LineageInput, lineage_outputs}; use crate::bindings::models::ProjectCatalog; use crate::bindings::types::CompilerDetach; @@ -33,8 +35,8 @@ type ModelInput = ( String, String, String, - Vec, - Vec, + Option>, + Option>, Vec, Option, ); @@ -66,14 +68,16 @@ type OutcomeRow = ( Vec, ); -/// Recover, explain and reject opt-outs on `catalog`'s analysis pool. +/// Recover, explain and reject opt-outs, reading facts the payload omits from `session`. #[pyfunction] +#[pyo3(signature = (catalog, request, session=None))] fn complete_semantic_checks( py: Python<'_>, catalog: PyRef<'_, ProjectCatalog>, request: RequestInput, + session: Option>, ) -> PyResult { - let request = completion_request(request); + let request = completion_request(request, session.as_deref()).map_err(compiler_error)?; let catalog = &catalog.inner; let outcome = py .compiler_detach(|| complete_semantic_diagnostics(&request, catalog)) @@ -106,13 +110,19 @@ fn location_row(location: SemanticLocation) -> LocationRow { ) } -fn completion_request((dialect, diagnostics, models, shapes): RequestInput) -> CompletionRequest { - CompletionRequest { +fn completion_request( + (dialect, diagnostics, models, shapes): RequestInput, + session: Option<&NativeModelAnalysisSession>, +) -> Result { + Ok(CompletionRequest { dialect, diagnostics: diagnostics.into_iter().map(semantic_diagnostic).collect(), - models: models.into_iter().map(completion_model).collect(), + models: models + .into_iter() + .map(|model| completion_model(model, session)) + .collect::>()?, shapes, - } + }) } fn semantic_diagnostic( @@ -134,8 +144,20 @@ fn semantic_diagnostic( fn completion_model( (name, query_sql, authored_sql, inferred_columns, lineage, binding_codes, opt_out): ModelInput, -) -> CompletionModel { - CompletionModel { + session: Option<&NativeModelAnalysisSession>, +) -> Result { + let inferred_columns: Vec = match inferred_columns { + Some(names) => names, + None => session_model_facts(session, &name)? + .columns + .clone() + .unwrap_or_default(), + }; + let lineage: Vec = match lineage { + Some(lineage) => lineage, + None => session_model_facts(session, &name)?.lineage.clone(), + }; + Ok(CompletionModel { name, query_sql, authored_sql, @@ -143,7 +165,7 @@ fn completion_model( lineage: lineage_outputs(lineage), binding_codes, rejected_opt_out_file: opt_out, - } + }) } fn completed_row(diagnostic: CompletedDiagnostic) -> CompletedRow { diff --git a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/mod.rs b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/mod.rs index 581ba801c2..1565c82749 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/mod.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/mod.rs @@ -1,4 +1,5 @@ pub(crate) mod completion; pub(crate) mod metadata; pub(crate) mod registration; +pub(crate) mod session_facts; pub(crate) mod type_recovery; diff --git a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/session_facts.rs b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/session_facts.rs new file mode 100644 index 0000000000..eaf244fa10 --- /dev/null +++ b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/session_facts.rs @@ -0,0 +1,18 @@ +//! Model output names and lineage the semantic stages read from a finished analysis session. + +use sqlbuild_analysis::assembly::analysis_session::main::finished_model_facts::finished_model_facts; +use sqlbuild_analysis::assembly::analysis_session::models::SessionModelFacts; + +use crate::bindings::_helpers::analysis_session::session::NativeModelAnalysisSession; + +/// The facts the finished `session` kept for model `name`, which the payload left out. +pub(crate) fn session_model_facts<'a>( + session: Option<&'a NativeModelAnalysisSession>, + name: &str, +) -> Result<&'a SessionModelFacts, String> { + let finished = session + .and_then(NativeModelAnalysisSession::finished_session) + .ok_or("a model asked for session facts without a finished session")?; + finished_model_facts(finished, name) + .ok_or_else(|| format!("the finished session kept no facts for model {name}")) +} diff --git a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/type_recovery.rs b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/type_recovery.rs index 29d48a1739..801971e2a4 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/type_recovery.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/semantic_checks/type_recovery.rs @@ -10,7 +10,9 @@ use sqlbuild_analysis::semantic_checks::models::{ }; use sqlbuild_analysis::semantic_checks::types::RevisedBinding; +use crate::bindings::_helpers::analysis_session::session::NativeModelAnalysisSession; use crate::bindings::_helpers::boundary::panics::compiler_error; +use crate::bindings::_helpers::semantic_checks::session_facts::session_model_facts; use crate::bindings::models::ProjectCatalog; use crate::bindings::types::CompilerDetach; @@ -22,7 +24,7 @@ type ModelInput = ( String, Option>, Vec, - Vec, + Option>, Vec<(usize, String, String, bool)>, Vec<(usize, String, String, Option, Option)>, ); @@ -84,14 +86,16 @@ impl SemanticTypeRecovery { } } -/// Plan type recovery on `catalog`'s analysis pool. +/// Plan type recovery, reading names and lineage from `session` for models with no lineage. #[pyfunction] +#[pyo3(signature = (catalog, request, session=None))] fn plan_semantic_type_recovery( py: Python<'_>, catalog: PyRef<'_, ProjectCatalog>, request: RequestInput, + session: Option>, ) -> PyResult { - let request = recovery_request(request); + let request = recovery_request(request, session.as_deref()).map_err(compiler_error)?; let catalog = &catalog.inner; let step = py .compiler_detach(|| plan_type_recovery(&request, catalog)) @@ -109,10 +113,16 @@ pub(crate) fn lineage_outputs(lineage: Vec) -> Vec .collect() } -fn recovery_request((dialect, models, diagnostics): RequestInput) -> TypeRecoveryRequest { - TypeRecoveryRequest { +fn recovery_request( + (dialect, models, diagnostics): RequestInput, + session: Option<&NativeModelAnalysisSession>, +) -> Result { + Ok(TypeRecoveryRequest { dialect, - models: models.into_iter().map(recovery_model).collect(), + models: models + .into_iter() + .map(|model| recovery_model(model, session)) + .collect::>()?, diagnostics: diagnostics .into_iter() .map(|(id, code, is_model, resource_name)| DiagnosticOwner { @@ -122,13 +132,21 @@ fn recovery_request((dialect, models, diagnostics): RequestInput) -> TypeRecover resource_name, }) .collect(), - } + }) } fn recovery_model( (name, query_sql, inferred_columns, references, lineage, bindings, raw_bindings): ModelInput, -) -> RecoveryModel { - RecoveryModel { + session: Option<&NativeModelAnalysisSession>, +) -> Result { + let (inferred_columns, lineage) = match lineage { + Some(lineage) => (inferred_columns, lineage), + None => { + let facts = session_model_facts(session, &name)?; + (facts.columns.clone(), facts.lineage.clone()) + } + }; + Ok(RecoveryModel { name, query_sql, inferred_columns, @@ -153,7 +171,7 @@ fn recovery_model( end, }) .collect(), - } + }) } pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { diff --git a/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/assembly.rs b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/assembly.rs new file mode 100644 index 0000000000..8769cb3b70 --- /dev/null +++ b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/assembly.rs @@ -0,0 +1,253 @@ +//! Assemble compiled SQL test facts from compile inputs' own objects, without a JSON request. + +use pyo3::exceptions::PyValueError; +use pyo3::prelude::{Bound, PyAny, PyAnyMethods, PyModule, PyModuleMethods, PyResult, Python}; +use pyo3::{FromPyObject, PyErr, pyfunction, wrap_pyfunction}; +use sqlbuild_analysis::compiler::main::sql_test_assembly::assemble_sql_test_batch; +use sqlbuild_analysis::compiler::models::{ + AssembledSqlTestFacts, SqlTestAssemblyBatch, SqlTestAssemblyModel, SqlTestAssemblyModelPayload, + SqlTestAssemblyOutcome, SqlTestAssemblyPayload, SqlTestAssemblyReference, SqlTestAssemblyTest, + SqlTestCte, SqlTestParameterValue, +}; + +use crate::bindings::_helpers::boundary::panics::value_error; +use crate::bindings::_helpers::sqltext::lexical_syntax::LexicalSyntaxInput; +use crate::bindings::types::CompilerDetach; + +const MACRO_TOKEN: char = '@'; + +/// `(line, column, end line, end column, message, help)` of one P013 diagnostic. +type DiagnosticRow = (usize, usize, usize, usize, String, String); +/// `(name, scope deps, target models, case fingerprint, diagnostic resource, diagnostics)`. +type FactsRow = ( + String, + Vec<(&'static str, String)>, + Vec, + Option, + String, + Vec, +); +/// The test's facts, or the deferral kind of a test Python assembles. +type AssemblyRow = (Option, Option<&'static str>); + +/// The Python assembly request: the project's model inputs and the SQL test inputs. +#[derive(FromPyObject)] +struct AssemblyRequest<'py> { + #[pyo3(attribute)] + model_inputs: Vec>, + #[pyo3(attribute)] + test_inputs: Vec>, + #[pyo3(attribute)] + lexical_syntax: LexicalSyntaxInput, +} + +/// Each test input's assembled facts, or the deferral of a test Python must assemble. +#[pyfunction] +fn assemble_compiled_sql_tests( + py: Python<'_>, + request: AssemblyRequest<'_>, +) -> PyResult> { + let batch = SqlTestAssemblyBatch { + models: request + .model_inputs + .iter() + .map(assembly_model) + .collect::>()?, + tests: request + .test_inputs + .iter() + .map(assembly_test) + .collect::>()?, + lexical_syntax: request.lexical_syntax.into(), + }; + let outcomes = py + .compiler_detach(|| Ok(assemble_sql_test_batch(&batch))) + .map_err(value_error)?; + Ok(outcomes.into_iter().map(assembly_row).collect()) +} + +fn assembly_model(model: &Bound<'_, PyAny>) -> PyResult { + let macro_deps: Vec = model.getattr("macro_deps")?.extract()?; + let unscanned_macro_source = if macro_deps.is_empty() { + Some(model.getattr("macro_source_sql")?.extract::()?) + .filter(|sql| sql.contains(MACRO_TOKEN)) + } else { + None + }; + Ok(SqlTestAssemblyModel { + name: model + .getattr("model_file")? + .getattr("file_path")? + .getattr("stem")? + .extract()?, + macro_deps, + unscanned_macro_source, + references: model + .getattr("references")? + .try_iter()? + .map(|reference| { + let reference = reference?; + Ok(SqlTestAssemblyReference { + kind: reference.getattr("ref_kind")?.extract()?, + name: reference.getattr("ref_name")?.extract()?, + package: reference.getattr("ref_package")?.extract()?, + }) + }) + .collect::>()?, + }) +} + +fn assembly_test(test: &Bound<'_, PyAny>) -> PyResult { + let test_file = test.getattr("test_file")?; + let test_block = test.getattr("test_block")?; + let relative_path = test_file.getattr("relative_path")?; + let payload = test.getattr("payload")?; + let payload = if payload.hasattr("actual_cte")? { + SqlTestAssemblyPayload::Direct { + mode: payload.getattr("mode")?.extract()?, + tested_resource_names: payload.getattr("tested_resource_names")?.extract()?, + } + } else { + SqlTestAssemblyPayload::Model(SqlTestAssemblyModelPayload { + authored_ctes: ctes(&payload, "authored_ctes")?, + expected_ctes: ctes(&payload, "expected_ctes")?, + assertion_ctes: ctes(&payload, "assertion_ctes")?, + expected_model_names: payload.getattr("expected_model_names")?.extract()?, + assertion_target_model_names: payload + .getattr("assertion_target_model_names")? + .extract()?, + reference_target_model_names: payload + .getattr("reference_target_model_names")? + .extract()?, + mock_model_names: payload.getattr("mock_model_names")?.extract()?, + has_macro_mocks: payload.getattr("macro_mocks")?.is_truthy()?, + }) + }; + Ok(SqlTestAssemblyTest { + block_name: test_block.getattr("name")?.extract()?, + file_stem: test_file.getattr("file_path")?.getattr("stem")?.extract()?, + relative_path: relative_path.call_method0("as_posix")?.extract()?, + relative_stem: relative_path.getattr("stem")?.extract()?, + contents: test_file.getattr("contents")?.extract()?, + block_sql: test_block.getattr("sql_body")?.extract()?, + block_index: test_block.getattr("test_index")?.extract()?, + sql_body: test.getattr("sql_body")?.extract()?, + case_name: test.getattr("case_name")?.extract()?, + parameter_schema: test + .getattr("parameter_schema")? + .try_iter()? + .map(|parameter| { + let parameter = parameter?; + Ok(( + parameter.getattr("name")?.extract()?, + parameter.getattr("value_type")?.extract()?, + parameter.getattr("nullable")?.extract()?, + )) + }) + .collect::>()?, + parameter_values: test + .getattr("parameter_values")? + .try_iter()? + .map(|entry| { + let (name, value): (String, Bound<'_, PyAny>) = entry?.extract()?; + Ok((name, parameter_value(&value)?)) + }) + .collect::>()?, + payload, + }) +} + +fn ctes(owner: &Bound<'_, PyAny>, attribute: &str) -> PyResult> { + owner + .getattr(attribute)? + .try_iter()? + .map(|value| { + let value = value?; + Ok(SqlTestCte { + name: value.getattr("name")?.extract()?, + sql_body: value.getattr("sql_body")?.extract()?, + }) + }) + .collect() +} + +/// One `SqlValue`, read by its logical kind; decimals keep `as_tuple()`'s digits. +fn parameter_value(value: &Bound<'_, PyAny>) -> PyResult { + let kind: String = value.getattr("logical_type")?.getattr("kind")?.extract()?; + let payload = value.getattr("value")?; + Ok(match kind.as_str() { + "string" => SqlTestParameterValue::String(payload.extract()?), + "integer" => SqlTestParameterValue::Integer(payload.extract()?), + "boolean" => SqlTestParameterValue::Boolean(payload.extract()?), + "float" => SqlTestParameterValue::Float(payload.extract()?), + "decimal" => { + let (sign, digits, exponent): (u8, Vec, i64) = + payload.call_method0("as_tuple")?.extract()?; + SqlTestParameterValue::Decimal { + negative: sign == 1, + digits, + exponent, + } + } + "null" => SqlTestParameterValue::Null, + "list" => SqlTestParameterValue::List(parameter_values(&payload)?), + "set" => SqlTestParameterValue::Set(parameter_values(&payload)?), + "object" => SqlTestParameterValue::Object( + payload + .try_iter()? + .map(|entry| { + let (key, item): (String, Bound<'_, PyAny>) = entry?.extract()?; + Ok((key, parameter_value(&item)?)) + }) + .collect::>()?, + ), + other => { + return Err(PyErr::new::(format!( + "unknown SQL value kind {other:?}" + ))); + } + }) +} + +fn parameter_values(items: &Bound<'_, PyAny>) -> PyResult> { + items + .try_iter()? + .map(|item| parameter_value(&item?)) + .collect() +} + +fn assembly_row(outcome: SqlTestAssemblyOutcome) -> AssemblyRow { + match outcome { + SqlTestAssemblyOutcome::Assembled(facts) => (Some(facts_row(facts)), None), + SqlTestAssemblyOutcome::Deferred(deferral) => (None, Some(deferral.as_str())), + } +} + +fn facts_row(facts: AssembledSqlTestFacts) -> FactsRow { + ( + facts.name, + facts.scope_deps, + facts.target_model_names, + facts.case_fingerprint, + facts.diagnostic_resource_name, + facts + .diagnostics + .into_iter() + .map(|diagnostic| { + ( + diagnostic.line, + diagnostic.column, + diagnostic.end_line, + diagnostic.end_column, + diagnostic.message, + diagnostic.help, + ) + }) + .collect(), + ) +} + +pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { + module.add_function(wrap_pyfunction!(assemble_compiled_sql_tests, module)?)?; + Ok(()) +} diff --git a/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/mod.rs b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/mod.rs index 8be67c2871..75d847c142 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/mod.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/mod.rs @@ -1,2 +1,3 @@ +pub(crate) mod assembly; pub(crate) mod planning; pub(crate) mod registration; diff --git a/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/registration.rs b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/registration.rs index d7cf7c6c23..ac702ccbfd 100644 --- a/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/registration.rs +++ b/crates/sqlbuild-python/src/bindings/_helpers/sql_test_glue/registration.rs @@ -1,9 +1,10 @@ -//! Register the native SQL test planning functions. +//! Register the native SQL test planning and assembly functions. use pyo3::prelude::{Bound, PyModule, PyResult}; -use crate::bindings::_helpers::sql_test_glue::planning; +use crate::bindings::_helpers::sql_test_glue::{assembly, planning}; pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> { - planning::register(module) + planning::register(module)?; + assembly::register(module) } diff --git a/scripts/compile_performance_ratio/_helpers/measure.py b/scripts/compile_performance_ratio/_helpers/measure.py index 9931aefcc4..27a314ad22 100644 --- a/scripts/compile_performance_ratio/_helpers/measure.py +++ b/scripts/compile_performance_ratio/_helpers/measure.py @@ -20,6 +20,7 @@ BASE_LABEL, COLD_MODE, COMPILE_ENTRY, + COMPILER_ENGINE_KEY, DENSE_KIND, EDIT_MODE, ERROR_TAIL_CHARACTERS, @@ -116,34 +117,54 @@ def compare_builds( head_python: Path, runs: int, modes: tuple[str, ...], + engines: tuple[str | None, str | None] = (None, None), + compile_args: tuple[str, ...] = (), ) -> tuple[CompileComparison, ...]: """Alternate base and head compiles per mode; warm and edit reuse the cold project.""" - builds: tuple[tuple[str, Path, Path], ...] = ( - (BASE_LABEL, base_python, base_project_dir), - (HEAD_LABEL, head_python, head_project_dir), + base_engine, head_engine = engines + builds: tuple[tuple[str, Path, Path, str | None], ...] = ( + (BASE_LABEL, base_python, base_project_dir, base_engine), + (HEAD_LABEL, head_python, head_project_dir, head_engine), ) comparisons: list[CompileComparison] = [] cache_primed: bool = False for mode in modes: print(f"Comparing {MODE_TITLES[mode]} over {runs} alternating runs", file=sys.stderr) if mode == COLD_MODE: - for label, python, project_dir in builds: - _ = _compile_once(label=label, python=python, project_dir=project_dir, mode=mode) + for label, python, project_dir, engine in builds: + _ = _compile_once( + label=label, + python=python, + project_dir=project_dir, + mode=mode, + engine=engine, + compile_args=compile_args, + ) cache_primed = False elif not cache_primed: - for label, python, project_dir in builds: + for label, python, project_dir, engine in builds: _ = _compile_once( - label=label, python=python, project_dir=project_dir, mode=WARM_MODE + label=label, + python=python, + project_dir=project_dir, + mode=WARM_MODE, + engine=engine, + compile_args=compile_args, ) cache_primed = True results: dict[str, list[CompileRun]] = {BASE_LABEL: [], HEAD_LABEL: []} for revision in range(runs): - for label, python, project_dir in builds: + for label, python, project_dir, engine in builds: if mode == EDIT_MODE: _ = apply_one_model_edit(project_dir=project_dir, revision=revision) run: CompileRun = _compile_once( - label=label, python=python, project_dir=project_dir, mode=mode + label=label, + python=python, + project_dir=project_dir, + mode=mode, + engine=engine, + compile_args=compile_args, ) _check_cache_use(run=run, mode=mode) results[label].append(run) @@ -170,8 +191,8 @@ def _comparison( head_wall_seconds=statistics.median(run.wall_seconds for run in head), base_cpu_seconds=statistics.median(run.cpu_seconds for run in base), head_cpu_seconds=statistics.median(run.cpu_seconds for run in head), - base_timings_ms=_median_phases(runs=base), - head_timings_ms=_median_phases(runs=head), + base_timings_ms=median_phases(runs=base), + head_timings_ms=median_phases(runs=head), ) @@ -191,12 +212,22 @@ def _check_cache_use(*, run: CompileRun, mode: str) -> None: ) -def _compile_once(*, label: str, python: Path, project_dir: Path, mode: str) -> CompileRun: +def _compile_once( + *, + label: str, + python: Path, + project_dir: Path, + mode: str, + engine: str | None, + compile_args: tuple[str, ...], +) -> CompileRun: cache_args: tuple[str, ...] = () if mode == COLD_MODE: shutil.rmtree(project_dir / "target", ignore_errors=True) cache_args = ("--no-cache",) environment: dict[str, str] = _compile_environment() + if engine is not None: + environment[COMPILER_ENGINE_KEY] = engine before: resource.struct_rusage = resource.getrusage(resource.RUSAGE_CHILDREN) started: float = time.perf_counter() completed: subprocess.CompletedProcess[str] = subprocess.run( @@ -210,6 +241,7 @@ def _compile_once(*, label: str, python: Path, project_dir: Path, mode: str) -> "compile", "--json", *cache_args, + *compile_args, ], capture_output=True, text=True, @@ -247,9 +279,12 @@ def _compile_environment() -> dict[str, str]: } -def _median_phases(*, runs: list[CompileRun]) -> dict[str, float]: +def median_phases(*, runs: list[CompileRun]) -> dict[str, float]: + """Return each phase's median over runs, omitting phases any run did not report.""" + medians: dict[str, float] = {} for phase in REPORTED_PHASES: - values: list[int] = [run.timings_ms.get(phase, 0) for run in runs] - medians[phase] = statistics.median(values) + values: list[int] = [run.timings_ms[phase] for run in runs if phase in run.timings_ms] + if values and len(values) == len(runs): + medians[phase] = statistics.median(values) return medians diff --git a/scripts/compile_performance_ratio/_helpers/report.py b/scripts/compile_performance_ratio/_helpers/report.py index 84cdd7589e..aabf811eea 100644 --- a/scripts/compile_performance_ratio/_helpers/report.py +++ b/scripts/compile_performance_ratio/_helpers/report.py @@ -18,6 +18,9 @@ def comparison_markdown( per_side_projects: bool, failures: tuple[str, ...], mode_max_ratios: Mapping[str, float] | None = None, + engines: tuple[str | None, str | None] = (None, None), + gate_phases: tuple[str, ...] = (), + compile_args: tuple[str, ...] = (), ) -> str: """Summarize medians, ratios and per-phase timings of every mode as Markdown tables.""" @@ -27,6 +30,18 @@ def comparison_markdown( else "One project generated with head's generator and compiled by both builds." ) lines: list[str] = [] + base_engine, head_engine = engines + if base_engine is not None or head_engine is not None: + lines.extend( + ( + f"Engines: base `{base_engine or 'default'}`, head `{head_engine or 'default'}`.", + "", + ) + ) + if gate_phases: + lines.extend((f"Gated phases: {', '.join(gate_phases)}.", "")) + if compile_args: + lines.extend((f"Compile arguments: `{' '.join(compile_args)}`.", "")) for comparison in comparisons: lines.extend( ( diff --git a/scripts/compile_performance_ratio/_helpers/verdict.py b/scripts/compile_performance_ratio/_helpers/verdict.py index cca469c30b..4267778723 100644 --- a/scripts/compile_performance_ratio/_helpers/verdict.py +++ b/scripts/compile_performance_ratio/_helpers/verdict.py @@ -47,5 +47,38 @@ def ratio_failures( return tuple(failures) +def phase_failures( + *, + comparisons: tuple[CompileComparison, ...], + modes: tuple[str, ...], + phases: tuple[str, ...], + max_ratio: float, + noise_floor_ms: float, +) -> tuple[str, ...]: + """Describe every gated phase that is unmeasured or slower than ratio plus floor allow.""" + + measured: dict[str, CompileComparison] = { + comparison.mode: comparison for comparison in comparisons + } + failures: list[str] = [] + for mode in modes: + comparison: CompileComparison | None = measured.get(mode) + if comparison is None: + failures.append(f"{mode}: no measurement") + continue + for phase in phases: + prefix: str = f"{comparison.kind} {comparison.models} {mode} {phase}" + base: float | None = comparison.base_timings_ms.get(phase) + head: float | None = comparison.head_timings_ms.get(phase) + if base is None or head is None: + failures.append(f"{prefix}: not reported") + elif head > base * max_ratio + noise_floor_ms: + failures.append( + f"{prefix}: {head:.0f} ms exceeds {max_ratio:.2f}x base {base:.0f} ms " + f"plus {noise_floor_ms:.0f} ms" + ) + return tuple(failures) + + def _measured(seconds: float) -> bool: return math.isfinite(seconds) and seconds > 0 diff --git a/scripts/compile_performance_ratio/constants.py b/scripts/compile_performance_ratio/constants.py index ca1301ec6a..2c061917a9 100644 --- a/scripts/compile_performance_ratio/constants.py +++ b/scripts/compile_performance_ratio/constants.py @@ -34,6 +34,8 @@ "kind=sys.argv[1], project_dir=Path(sys.argv[2]), models=int(sys.argv[3]))" ) PYTHONPATH_KEY: str = "PYTHONPATH" +COMPILER_ENGINE_KEY: str = "SQLBUILD_COMPILER_ENGINE" +PHASE_NOISE_FLOOR_MS: float = 50.0 ERROR_TAIL_CHARACTERS: int = 2000 FRESH_SOURCE_SHARE: float = 713 / 3000 FRESH_SEED_SHARE: float = 141 / 3000 @@ -45,9 +47,13 @@ "total_ms", "graph_ms", "model_analysis_ms", + "model_analysis_cpu_ms", "analysis_native_ms", + "contracts_ms", + "contracts_cpu_ms", "built_in_rules_ms", "custom_rules_ms", + "custom_rules_cpu_ms", "test_planning_ms", "write_ms", ) diff --git a/scripts/compile_performance_ratio/main/compare.py b/scripts/compile_performance_ratio/main/compare.py index 330bc2704d..cbf0cbbe29 100644 --- a/scripts/compile_performance_ratio/main/compare.py +++ b/scripts/compile_performance_ratio/main/compare.py @@ -14,14 +14,16 @@ write_benchmark_project, ) from scripts.compile_performance_ratio._helpers.report import append_summary, comparison_markdown -from scripts.compile_performance_ratio._helpers.verdict import ratio_failures +from scripts.compile_performance_ratio._helpers.verdict import phase_failures, ratio_failures from scripts.compile_performance_ratio.constants import ( COMPILE_MODES, DEFAULT_MAX_RATIO, DEFAULT_RUNS, EDIT_MODE, NOISE_FLOOR_SECONDS, + PHASE_NOISE_FLOOR_MS, PROJECT_KINDS, + REPORTED_PHASES, ) from scripts.compile_performance_ratio.models import CompileComparison @@ -59,16 +61,29 @@ def compare_compile_performance(argv: list[str] | None = None) -> int: head_python=args.head_python, runs=args.runs, modes=modes, + engines=(args.base_engine, args.head_engine), + compile_args=tuple(args.compile_args), ) mode_max_ratios: dict[str, float] = ( {} if args.edit_max_ratio is None else {EDIT_MODE: args.edit_max_ratio} ) - failures: tuple[str, ...] = ratio_failures( - comparisons=comparisons, - modes=modes, - max_ratio=args.max_ratio, - noise_floor_seconds=args.noise_floor_seconds, - mode_max_ratios=mode_max_ratios, + gate_phases: tuple[str, ...] = tuple(dict.fromkeys(args.gate_phases)) + failures: tuple[str, ...] = ( + phase_failures( + comparisons=comparisons, + modes=modes, + phases=gate_phases, + max_ratio=args.max_ratio, + noise_floor_ms=args.phase_noise_floor_ms, + ) + if gate_phases + else ratio_failures( + comparisons=comparisons, + modes=modes, + max_ratio=args.max_ratio, + noise_floor_seconds=args.noise_floor_seconds, + mode_max_ratios=mode_max_ratios, + ) ) markdown: str = comparison_markdown( comparisons=comparisons, @@ -77,6 +92,9 @@ def compare_compile_performance(argv: list[str] | None = None) -> int: per_side_projects=per_side_projects, failures=failures, mode_max_ratios=mode_max_ratios, + engines=(args.base_engine, args.head_engine), + gate_phases=gate_phases, + compile_args=tuple(args.compile_args), ) print(markdown) _ = append_summary(path=Path(summary_value) if summary_value else None, markdown=markdown) @@ -122,4 +140,35 @@ def _parse_args(argv: list[str] | None) -> argparse.Namespace: default=NOISE_FLOOR_SECONDS, help="Seconds of slack added to the ratio allowance before a slowdown fails.", ) + parser.add_argument( + "--base-engine", + default=None, + help="Compiler engine the base build runs; defaults to the build's own default.", + ) + parser.add_argument( + "--head-engine", + default=None, + help="Compiler engine the head build runs; defaults to the build's own default.", + ) + parser.add_argument( + "--compile-arg", + dest="compile_args", + action="append", + default=[], + help="Extra `sqb compile` argument for both builds, e.g. `--compile-arg=--select=*`.", + ) + parser.add_argument( + "--gate-phase", + dest="gate_phases", + action="append", + choices=REPORTED_PHASES, + default=[], + help="Gate only this reported phase's median instead of whole-compile wall and CPU.", + ) + parser.add_argument( + "--phase-noise-floor-ms", + type=float, + default=PHASE_NOISE_FLOOR_MS, + help="Milliseconds of slack added to a gated phase's ratio allowance.", + ) return parser.parse_args(argv) diff --git a/scripts/compiler_differential/README.md b/scripts/compiler_differential/README.md new file mode 100644 index 0000000000..20a0a1e65e --- /dev/null +++ b/scripts/compiler_differential/README.md @@ -0,0 +1,147 @@ +# Compiler differential + +`make compiler-differential` compiles fixtures, examples, generated seeds and the failure corpus +under two compiler engines and fails on the first differing artifact. `make +compiler-differential-shipped` does the same for the shipped `native` default. Both also enforce +the shared gates below. + +For ad hoc runs (one project, other seeds, other engines), call the script directly, for example +`uv run python -m scripts.run_compiler_differential --corpus --project --engines python +native`. The make targets fix the corpus the allow-list and goldens are recorded for. + +## Shared gates for native ports + +A port that moves work from the Python compiler to native code reuses these three mechanisms. It +does not add its own parity harness, property suite or E2E file. + +### Native-to-Python fallbacks and analysis deferrals + +`native_fallbacks.toml` is the one allow-list of all work native code still hands back to Python, +and of the work each native stage answers itself. It covers three kinds of record: +- fallbacks, from `report_native_fallback(site=NativeFallbackSite., kind=...)` on every + path where a native stage hands work to Python, or runs Python with no native path yet; +- preview analysis-stage deferrals: every `analysis-deferrals-*.jsonl` record (analysis session, + lineage, semantic checks, contracts); +- native answers, from `report_native_answer(stage=NativeStage., kind=...)` where a + stage's native path produced the result: files, models, scans or calls. Their site is + `.native`. + +Counting only fallbacks cannot tell a stage that answers natively from one that no longer runs +natively at all. The answer counts can: if a stage is switched to Python, its `.native` +entries vanish and the gate says so. + +Every entry names an engine, stage, site and kind, with its exact count per corpus. Use +`max_counts` instead of `counts` only for a count that is not stable, and give the reason in a +comment and in the PR body. + +The records cost nothing unless `SQLBUILD_ANALYSIS_RECORD_DIR` is set, which only the harness +sets. `--native-fallbacks check` runs in both make targets and fails CI in both directions: +- an entry, engine or corpus count that is not on the list fails; +- a listed entry whose count changed or that no longer occurs also fails, and the message says to + update or remove it, so the fallback list only shrinks; +- a vanished native answer fails as work that now runs in Python; +- a listed fallback that vanished is refused outright, with "fallback disappeared but native + answers did not appear; the stage may be switched off", unless the same engine, stage and + corpus report more `.native` answers than the list records. A stage with only fallback + entries (`sql_test_glue`, `project_assembly`) would otherwise look like a finished port when it + is switched off. + +The counts hold for the make targets' corpus (`--seeds 12`); other seed ranges are refused. + +Two stages the list cannot watch: +- `type_system`: the compile corpus never reaches type normalization. Its callers are the planner + and executor and the preview stages' Python fallbacks. `tests/integration/.../type_system/ + test_native_type_parity.py` proves instead that the public `normalize_type` asks native first + under `native-preview`. +- `discovery.native model_file_listings`: it is reported unconditionally inside the native model + file discovery, which has no fallback to Python, so this count cannot detect anything. It stays + only as a record that native discovery ran. + +**How a PR updates the list and the goldens** + +One command rewrites both from the current tree: + +```sh +make compiler-baselines +``` + +It deletes `tests/goldens/compiler`, then runs the two CI differentials with `--native-fallbacks +update --goldens update`. Commit the resulting `native_fallbacks.toml` and `tests/goldens/` diff +in the same PR as the change that caused it. + +- A port deletes the Python code it replaces in the same PR. Its fallback entries then disappear + from the list, and that removal is the port's test that the fallbacks are gone. Its answer + counts usually rise. When the last entry for a `NativeFallbackSite` goes, delete the member + and its `report_native_fallback` call too. +- If the corpus does not reach a site yet, first add a failure case or seed feature that does. +- A PR that merges after a list or golden change on main reruns `make compiler-baselines` after + rebasing and commits the result. + +**What a reviewer checks in the diff** + +- `native_fallbacks.toml`: + - Removed fallback entries and lower fallback counts are expected from ports. + - Every added fallback entry, higher fallback count or new `max_counts` needs a stated reason + in the PR body. Never add one just to make CI pass. + - A removed or lower `.native` answer count means less native work. It needs a reason + in the PR body. + - A removed fallback entry needs new or higher `.native` answers for the same stage in the + same diff: the port must report the work it now answers. A fallback that vanished with no new + answers is a stage switched off, not a port; the gate refuses it. +- Code: every new path that hands work to Python calls `report_native_fallback`, and every new + native path calls `report_native_answer` where its result is used. +- Goldens: + - Every changed golden is an intended output change, named in the PR body. + - An output-neutral port changes no golden. + - New goldens belong to new corpus cases. +- Proof by sabotage: `test_native_fallback_gate.py` proves the gate by sabotage, so forcing a + native stage to defer everything must fail it. A new "native did the work" gate needs the same + proof. + +### Golden outputs + +`tests/goldens/compiler//.json` holds one project's compile outputs: +- each command's exit code and diagnostics; +- the compiled SQL, one array item per line; +- the manifest without its volatile metadata and the SQL it repeats. + +The project directory is masked as `` and the harness work directory as ``, +whether or not the path is resolved. The SQLBuild version, invocation ids and timings are also +masked. + +Goldens hold outputs only, not stage captures: a seed's captures are about 690 KB, too large to +review. Cache facts are covered by the incremental-versus-no-cache tests instead. + +- `--goldens check` (in both make targets) compares every engine with the goldens, so an + output-neutral port needs no new parity suite. +- `make compiler-baselines` rewrites them from the python oracle. Run it only when output + changes on purpose, and review the diff like code. +- `tests/goldens/compiler/seed_range.toml` records the seed range the goldens were written for. + Every seed in that range, and every fixture, example and failure case, must have a golden. + Seeds outside the range (ad hoc runs with more seeds) are skipped. A missing `seed_range.toml` + fails the check for every seed project rather than skipping them. +- Dialect variants (`-postgres`, `-snowflake`) are generated for the first seed of a + run only, so a golden is required only for the variants of the recorded `seed_start`. An ad hoc + `--seed-start N` run checks its base seeds in the range and skips its variants. +- Once the Python stages are deleted, goldens are rewritten from `native`. + +### All-engine user-facing errors + +`engine_error_cases()` in `_helpers/corpus/failure_cases.py` lists user-facing errors with their +exact text. Each case is part of the failure corpus, so it runs in both differentials and has a +golden. It also runs in +`tests/e2e/scripts/compiler_differential/test_engine_error_cases.py` on the `python`, `native` +and `native-preview` engines, which must all report its `expected_code` and `expected_message`. + +A port that adds or changes a user-facing error adds one `failure_case(...)` to it: + +```python +failure_case( + name="engine-error-", + expected_code="P001", + files=mart_body_files("SELECT ...\n"), + expected_message=" for the project path>", +) +``` + +Then it runs `make compiler-baselines` to record the new case's golden. diff --git a/scripts/compiler_differential/_helpers/analysis_corpus/analysis_session.py b/scripts/compiler_differential/_helpers/analysis_corpus/analysis_session.py index 4a7c34a23e..c769c944bd 100644 --- a/scripts/compiler_differential/_helpers/analysis_corpus/analysis_session.py +++ b/scripts/compiler_differential/_helpers/analysis_corpus/analysis_session.py @@ -26,6 +26,13 @@ def _pivot_model(*, pivot_column: str, body: str) -> str: ) +def _contract_header(columns: str) -> str: + return ( + 'MODEL (\n description "Order totals per customer",\n contract enforced,\n' + f" columns (\n{columns} ),\n);\n\n" + ) + + def analysis_session_failure_cases() -> tuple[FailureCase, ...]: """Return this lane's failure cases; the lane appends here without editing shared lists.""" @@ -70,6 +77,29 @@ def analysis_session_failure_cases() -> tuple[FailureCase, ...]: f"SELECT customer_id, amount\nFROM (SELECT * FROM {_ORDERS}) staged\n", }, ), + failure_case( + name="analysis-session-cte-fact-type-mismatch", + expected_code="K002", + files={ + FAILURE_MART_PATH: _contract_header( + " customer_id (type INTEGER),\n total_amount (type VARCHAR),\n" + ) + + "WITH totals AS (\n SELECT customer_id, CAST(amount AS DOUBLE) AS total_amount\n" + f" FROM {_ORDERS}\n)\n" + "SELECT customer_id + 0 AS customer_id, total_amount FROM totals\n", + }, + ), + failure_case( + name="analysis-session-cte-fact-nullability", + expected_code="K004", + files={ + FAILURE_MART_PATH: _contract_header( + " customer_id (type INTEGER),\n note (type VARCHAR, nullable false),\n" + ) + + "WITH base AS (\n SELECT customer_id, CAST(NULL AS VARCHAR) AS note\n" + f" FROM {_ORDERS}\n)\nSELECT customer_id + 0 AS customer_id, note FROM base\n", + }, + ), failure_case( name="analysis-session-pivot-values-on-clause", expected_code="K011", diff --git a/scripts/compiler_differential/_helpers/analysis_corpus/semantic_checks.py b/scripts/compiler_differential/_helpers/analysis_corpus/semantic_checks.py index ddf0404a2c..753027e0f3 100644 --- a/scripts/compiler_differential/_helpers/analysis_corpus/semantic_checks.py +++ b/scripts/compiler_differential/_helpers/analysis_corpus/semantic_checks.py @@ -19,6 +19,13 @@ "amount, status", "amount, status, CAST('2026-01-01' AS TIMESTAMP) AS ordered_at" ) +_INTERMEDIATE_PATH: str = "models/intermediate/int_orders.sql" +_INTERMEDIATE: str = ( + 'MODEL (\n description "Doubled order amounts",\n);\n\n' + "SELECT customer_id, amount * 2 AS doubled_amount\n" + 'FROM __ref("stg_orders")\n' +) + _FUNCTION_PATH: str = "functions/sql/scaled_amount.sql" _SCALED_AMOUNT: str = ( "FUNCTION (\n" @@ -60,6 +67,24 @@ def semantic_checks_failure_cases() -> tuple[FailureCase, ...]: ), }, ), + failure_case( + name="semantic-recovered-uses-through-intermediate", + expected_code="B002", + expected_message="Unknown column 'amonut' in raw_orders", + expected_help="did you mean 'amount'?", + expected_notes=( + "raw_orders has: amount, status, customer_id, order_id", + "1 downstream uses of stg_orders.amount were not checked because of this error", + ), + files={ + **staging_files(FAILURE_BASE_STAGING.replace("amount, status", "amonut, status")), + _INTERMEDIATE_PATH: _INTERMEDIATE, + **mart_body_files( + "SELECT customer_id, SUM(doubled_amount) AS total_amount\n" + 'FROM __ref("int_orders")\nGROUP BY customer_id\n' + ), + }, + ), failure_case( name="semantic-qualified-alias-unknown-column", expected_code="B002", diff --git a/scripts/compiler_differential/_helpers/analysis_corpus/sql_test_glue.py b/scripts/compiler_differential/_helpers/analysis_corpus/sql_test_glue.py index 04d7b4b944..cc00d6d889 100644 --- a/scripts/compiler_differential/_helpers/analysis_corpus/sql_test_glue.py +++ b/scripts/compiler_differential/_helpers/analysis_corpus/sql_test_glue.py @@ -1,4 +1,4 @@ -"""Failure cases owned by the native SQL-test planning glue lane.""" +"""Failure cases owned by the native SQL-test planning and assembly glue lane.""" from scripts.compiler_differential._helpers.corpus.case_builder import failure_case from scripts.compiler_differential.models import FailureCase @@ -75,4 +75,23 @@ def sql_test_glue_failure_cases() -> tuple[FailureCase, ...]: ), ), ), + failure_case( + name="sql-test-glue-mock-reads-referencing-helper", + expected_code="P013", + expected_message=( + "SQL test mock '__ref__stg_orders' reads helper CTE 'orders_feed', which calls " + '__source("raw_orders"); mocks and fixtures are defined before the models the ' + "test runs, so the helper cannot be resolved for them" + ), + expected_location=(4, 31), + files=_test( + header='name "mock_reads_helper"', + ctes=( + 'orders_feed AS (SELECT * FROM __source("raw_orders")),\n' + "__ref__stg_orders AS (SELECT * FROM orders_feed),\n" + "__expected__customer_totals AS (\n" + " SELECT 10 AS customer_id, 5.0 AS total_amount\n)" + ), + ), + ), ) diff --git a/scripts/compiler_differential/_helpers/comparing/project_comparison.py b/scripts/compiler_differential/_helpers/comparing/project_comparison.py index f6c4227b1e..fc49bc08f1 100644 --- a/scripts/compiler_differential/_helpers/comparing/project_comparison.py +++ b/scripts/compiler_differential/_helpers/comparing/project_comparison.py @@ -13,6 +13,10 @@ from scripts.compiler_differential._helpers.coverage.analysis import project_analysis_kinds from scripts.compiler_differential._helpers.coverage.discovery import project_discovery_kinds from scripts.compiler_differential._helpers.coverage.render import project_render_kinds +from scripts.compiler_differential._helpers.goldens.goldens import ( + golden_differences, + golden_path_masks, +) from scripts.compiler_differential._helpers.running.evidence import keep_failure_evidence from scripts.compiler_differential._helpers.running.execution import run_engine from scripts.compiler_differential.constants import ( @@ -65,6 +69,17 @@ def compare_project(*, project: CorpusProject, options: DifferentialOptions) -> *_timeout_differences(project=project, runs=(left, right)), *_corpus_differences(project=project, run=left), *compare_engine_runs(project=project.name, left=left, right=right), + *( + golden_differences( + project=project, + runs=(left, right), + golden_dir=options.golden_dir, + mode=options.golden_mode, + masked_paths=golden_path_masks(case_dir=case_dir, work_dir=options.work_dir), + ) + if options.golden_mode is not None and options.golden_dir is not None + else () + ), ] if differences and options.evidence_dir is not None: _ = keep_failure_evidence( diff --git a/scripts/compiler_differential/_helpers/corpus/emitted_codes.py b/scripts/compiler_differential/_helpers/corpus/emitted_codes.py index c7c2af8612..4bfc505a39 100644 --- a/scripts/compiler_differential/_helpers/corpus/emitted_codes.py +++ b/scripts/compiler_differential/_helpers/corpus/emitted_codes.py @@ -12,9 +12,11 @@ first_diagnostic_message, ) from scripts.compiler_differential._helpers.corpus.corpus import build_corpus +from scripts.compiler_differential._helpers.goldens.goldens import golden_path_masks, masked_text from scripts.compiler_differential._helpers.running.execution import run_engine from scripts.compiler_differential.constants import ( ANALYSIS_CODE_SCAN_ROOTS, + COLD_COMPILE, CORPUS_FAILURES, DIAGNOSTIC_CODE_PATTERN, ERROR_SEVERITY, @@ -29,6 +31,8 @@ DifferentialOptions, EmittedCodes, EngineRun, + ExpectedOutcome, + FailureCase, ) from sqlbuild.compiler.auditing.constants import BUILT_IN_AUDIT_SHADOW_CODE from sqlbuild.compiler.compile import constants as compile_constants @@ -60,6 +64,20 @@ def emitted_failure_codes(*, options: DifferentialOptions) -> dict[str, EmittedC return {project.name: codes for project, codes in zip(corpus, emitted, strict=True)} +def case_emitted_codes(*, case: FailureCase, options: DifferentialOptions) -> EmittedCodes: + """Compile one failure case under the first engine and return what it really emitted.""" + + return _emitted_codes( + project=CorpusProject( + name=f"{CORPUS_FAILURES}/{case.name}", + commands=(COLD_COMPILE,), + expected=ExpectedOutcome(error_code=case.expected_code), + writer=case.write, + ), + options=options, + ) + + def discovery_error_codes() -> frozenset[str]: """Return the code of every `DiscoveryError` subclass, walking the whole hierarchy.""" @@ -182,14 +200,20 @@ def _emitted_codes(*, project: CorpusProject, options: DifferentialOptions) -> E options=options, ) first: dict[str, object] = first_diagnostic(outcome=run.outcomes[0], severity=ERROR_SEVERITY) + message: str | None = first_diagnostic_message(outcome=run.outcomes[0], severity=ERROR_SEVERITY) notes: object = first.get("notes") line: object = first.get("line") column: object = first.get("column") return EmittedCodes( errors=diagnostic_codes(outcome=run.outcomes[0], severity=ERROR_SEVERITY), warnings=diagnostic_codes(outcome=run.outcomes[0], severity=WARNING_SEVERITY), - first_error_message=first_diagnostic_message( - outcome=run.outcomes[0], severity=ERROR_SEVERITY + first_error_message=( + None + if message is None + else masked_text( + text=message, + masks=golden_path_masks(case_dir=case_dir, work_dir=options.work_dir), + ) ), first_error_help=None if first.get("help") is None else str(first.get("help")), first_error_notes=tuple(str(note) for note in notes) if isinstance(notes, list) else (), diff --git a/scripts/compiler_differential/_helpers/corpus/failure_cases.py b/scripts/compiler_differential/_helpers/corpus/failure_cases.py index c22ae06ca7..ed800bcd5f 100644 --- a/scripts/compiler_differential/_helpers/corpus/failure_cases.py +++ b/scripts/compiler_differential/_helpers/corpus/failure_cases.py @@ -36,6 +36,8 @@ ) from scripts.compiler_differential.models import FailureCase +_MART_HEADER_START: str = 'MODEL (\n description "Order totals per customer",\n' + _RULES_CONFIG: str = '\n[rules]\nselect = ["{codes}"]\n' @@ -57,6 +59,7 @@ def all_failure_cases() -> tuple[FailureCase, ...]: *reference_failure_cases(), *attachment_failure_cases(), *analysis_failure_cases(), + *engine_error_cases(), ) @@ -591,3 +594,51 @@ def _compile_failure_cases() -> tuple[FailureCase, ...]: ), ), ) + + +def engine_error_cases() -> tuple[FailureCase, ...]: + """User-facing errors every engine must report with the exact text; see the README.""" + + return ( + failure_case( + name="engine-error-unset-environment-variable", + expected_code="P001", + files=mart_body_files( + "SELECT customer_id, '@@ENV:SQB_ENGINE_ERROR_UNSET_REGION' AS region\n" + 'FROM __ref("stg_orders")\n' + ), + expected_message=( + "unknown environment variable '@@ENV:SQB_ENGINE_ERROR_UNSET_REGION' in " + f"'/{FAILURE_MART_PATH}'" + ), + ), + failure_case( + name="engine-error-case-folded-duplicate-column", + expected_code="P001", + files={ + FAILURE_MART_PATH: _MART_HEADER_START + + ' columns (\n Größe (description "Size"),\n' + + ' größe (description "Size again"),\n ),\n);\n\n' + + 'SELECT customer_id AS größe\nFROM __ref("stg_orders")\n' + }, + expected_message=( + f"{FAILURE_MART_PATH} model has duplicate column 'größe' " + "(column names are case-insensitive)" + ), + ), + failure_case( + name="engine-error-week-date-cursor-start", + expected_code="P001", + files={ + FAILURE_MART_PATH: _MART_HEADER_START + + " materialized incremental,\n incremental_strategy append,\n" + + " cursor order_ts,\n cursor_type timestamp,\n cursor_grain day,\n" + + ' cursor_start "2024-W01-1T25:00",\n);\n\n' + + 'SELECT customer_id, CURRENT_TIMESTAMP AS order_ts\nFROM __ref("stg_orders")\n' + }, + expected_message=( + "model 'customer_totals': cursor_start value '2024-W01-1T25:00' is not a valid " + "ISO timestamp: hour must be in 0..23" + ), + ), + ) diff --git a/scripts/compiler_differential/_helpers/goldens/__init__.py b/scripts/compiler_differential/_helpers/goldens/__init__.py new file mode 100644 index 0000000000..3da85fcf6d --- /dev/null +++ b/scripts/compiler_differential/_helpers/goldens/__init__.py @@ -0,0 +1 @@ +"""Golden compile outputs for the shipped native stages.""" diff --git a/scripts/compiler_differential/_helpers/goldens/goldens.py b/scripts/compiler_differential/_helpers/goldens/goldens.py new file mode 100644 index 0000000000..e5e2d3f837 --- /dev/null +++ b/scripts/compiler_differential/_helpers/goldens/goldens.py @@ -0,0 +1,239 @@ +"""Golden compile outputs: one reviewable JSON file per corpus project, checked or rewritten.""" + +from __future__ import annotations + +import json +import tomllib +from importlib.metadata import version +from pathlib import Path + +from scripts.compiler_differential._helpers.comparing.compare import ( + as_json_object, + first_json_difference, +) +from scripts.compiler_differential._helpers.comparing.normalize import ( + normalize_artifact_text, + normalize_stderr, +) +from scripts.compiler_differential.constants import ( + GOLDEN_CORPUS_PREFIXES, + GOLDEN_LABEL, + GOLDEN_MANIFEST_DROPPED_KEYS, + GOLDEN_MANIFEST_RESOURCE_SECTIONS, + GOLDEN_MISSING_HINT, + GOLDEN_MODE_CHECK, + GOLDEN_PATH_MASK, + GOLDEN_RESOURCE_DROPPED_FIELDS, + GOLDEN_SEED_CORPUS, + GOLDEN_SEED_RANGE_FILE, + GOLDEN_SUFFIX, + GOLDEN_VERSION_MASK, + GOLDEN_WORK_MASK, + PROJECT_DIRECTORY, +) +from scripts.compiler_differential.models import ( + CommandOutcome, + CorpusProject, + Difference, + Divergence, + EngineRun, +) + +_SQLBUILD_VERSION: str = version("sqlbuild") + + +def golden_differences( + *, + project: CorpusProject, + runs: tuple[EngineRun, ...], + golden_dir: Path, + mode: str, + masked_paths: tuple[tuple[str, str], ...], +) -> list[Difference]: + """Check every run against the project's golden, or rewrite it from the first (oracle) run.""" + + path: Path | None = golden_path(golden_dir=golden_dir, project=project.name) + if path is None: + return [] + payloads: list[dict[str, object]] = [ + golden_payload(run=run, masked_paths=masked_paths) for run in runs + ] + if mode != GOLDEN_MODE_CHECK: + path.parent.mkdir(parents=True, exist_ok=True) + _ = path.write_text(golden_text(payloads[0]), encoding="utf-8") + return [] + seed_range: Path = golden_dir / GOLDEN_SEED_RANGE_FILE + if path.parent.name == GOLDEN_SEED_CORPUS and not seed_range.is_file(): + return [ + Difference( + project=project.name, + artifact=f"golden {seed_range.name}", + location="file", + left="", + right=GOLDEN_MISSING_HINT, + labels=(GOLDEN_LABEL, "hint"), + ) + ] + if not path.is_file(): + if path.parent.name == GOLDEN_SEED_CORPUS and not _seed_in_recorded_range( + seed_range=seed_range, name=path.stem + ): + return [] + return [ + Difference( + project=project.name, + artifact=f"golden {path.name}", + location="file", + left="", + right=GOLDEN_MISSING_HINT, + labels=(GOLDEN_LABEL, "hint"), + ) + ] + golden: object = json.loads(path.read_text(encoding="utf-8")) + found: list[Difference] = [] + for run, payload in zip(runs, payloads, strict=True): + divergence: Divergence | None = first_json_difference(left=golden, right=payload) + if divergence is not None: + found.append( + Difference( + project=project.name, + artifact=f"golden ({run.engine})", + location=divergence.location, + left=divergence.left, + right=divergence.right, + labels=(GOLDEN_LABEL, run.engine), + ) + ) + return found + + +def golden_path(*, golden_dir: Path, project: str) -> Path | None: + """Where a corpus project's golden lives; projects outside the golden corpora have none.""" + + corpus, _, name = project.partition("/") + if corpus not in GOLDEN_CORPUS_PREFIXES or not name: + return None + return golden_dir / corpus / f"{name}{GOLDEN_SUFFIX}" + + +def golden_payload( + *, run: EngineRun, masked_paths: tuple[tuple[str, str], ...] +) -> dict[str, object]: + """Return a run's diagnostics, compiled SQL and slimmed manifest with run noise masked.""" + + return { + "commands": [ + _command(outcome=outcome, masked_paths=masked_paths) for outcome in run.outcomes + ], + "compiled": { + path: _lines( + text=_masked( + text=contents.decode("utf-8", "surrogateescape"), masked_paths=masked_paths + ) + ) + for path, contents in sorted(run.compiled.items()) + }, + "manifest": _manifest(text=run.manifest, masked_paths=masked_paths), + } + + +def golden_text(payload: dict[str, object]) -> str: + """Serialize a golden with one value per line so a changed output reads as a small diff.""" + + return json.dumps(payload, indent=1, ensure_ascii=False) + "\n" + + +def _command( + *, outcome: CommandOutcome, masked_paths: tuple[tuple[str, str], ...] +) -> dict[str, object]: + stdout: str = _masked(text=outcome.stdout, masked_paths=masked_paths) + try: + report: dict[str, object] | None = as_json_object(json.loads(stdout)) + except json.JSONDecodeError: + report = None + return { + "label": outcome.label, + "exit_code": "timed out" if outcome.timed_out else outcome.exit_code, + "diagnostics": ( + report.get("diagnostics", []) + if report is not None + else _lines( + text=normalize_stderr(_masked(text=outcome.stderr, masked_paths=masked_paths)) + ) + ), + } + + +def _manifest(*, text: str | None, masked_paths: tuple[tuple[str, str], ...]) -> object | None: + if text is None: + return None + manifest: dict[str, object] = ( + as_json_object(json.loads(_masked(text=text, masked_paths=masked_paths))) or {} + ) + kept: dict[str, object] = { + key: value for key, value in manifest.items() if key not in GOLDEN_MANIFEST_DROPPED_KEYS + } + for section in GOLDEN_MANIFEST_RESOURCE_SECTIONS: + resources: dict[str, object] = as_json_object(kept.get(section)) or {} + kept[section] = {name: _without_code(resource) for name, resource in resources.items()} + return kept + + +def _without_code(resource: object) -> object: + fields: dict[str, object] | None = as_json_object(resource) + if fields is None: + return resource + return { + key: value for key, value in fields.items() if key not in GOLDEN_RESOURCE_DROPPED_FIELDS + } + + +def _masked(*, text: str, masked_paths: tuple[tuple[str, str], ...]) -> str: + text = masked_text(text=text, masks=masked_paths) + return normalize_artifact_text(text).replace(_SQLBUILD_VERSION, GOLDEN_VERSION_MASK) + + +def _lines(*, text: str) -> list[str]: + return text.split("\n") + + +def write_golden_seed_range(*, golden_dir: Path, seed_start: int, seeds: int) -> None: + """Record the seed range the goldens hold; every seed in it must keep its golden.""" + + golden_dir.mkdir(parents=True, exist_ok=True) + _ = (golden_dir / GOLDEN_SEED_RANGE_FILE).write_text( + f"seed_start = {seed_start}\nseeds = {seeds}\n", encoding="utf-8" + ) + + +def _seed_in_recorded_range(*, seed_range: Path, name: str) -> bool: + """Seeds in the recorded range need goldens; dialect variants only for its first seed.""" + + recorded: dict[str, object] = tomllib.loads(seed_range.read_text(encoding="utf-8")) + start: int = int(str(recorded.get("seed_start", 0))) + seed, _, dialect = name.partition("-") + index: int = int(seed) + if dialect: + return index == start + return start <= index < start + int(str(recorded.get("seeds", 0))) + + +def golden_path_masks(*, case_dir: Path, work_dir: Path) -> tuple[tuple[str, str], ...]: + """`(path, token)` for the project and work directories, resolved or not, longest first.""" + + workspace: Path = case_dir / PROJECT_DIRECTORY + masks: set[tuple[str, str]] = { + (str(workspace), GOLDEN_PATH_MASK), + (str(workspace.resolve()), GOLDEN_PATH_MASK), + (str(work_dir), GOLDEN_WORK_MASK), + (str(work_dir.resolve()), GOLDEN_WORK_MASK), + } + return tuple(sorted(masks, key=lambda mask: (-len(mask[0]), mask[0]))) + + +def masked_text(*, text: str, masks: tuple[tuple[str, str], ...]) -> str: + """Replace every masked path with its token, longest path first.""" + + for path, token in masks: + text = text.replace(path, token) + return text diff --git a/scripts/compiler_differential/_helpers/running/native_fallbacks.py b/scripts/compiler_differential/_helpers/running/native_fallbacks.py new file mode 100644 index 0000000000..b9d50c366f --- /dev/null +++ b/scripts/compiler_differential/_helpers/running/native_fallbacks.py @@ -0,0 +1,246 @@ +"""The one allow-list of native-to-Python fallbacks and analysis deferrals, checked or rewritten.""" + +from __future__ import annotations + +import tomllib +from collections import Counter +from pathlib import Path + +from scripts.compiler_differential.constants import ( + CORPUS_SEEDS, + NATIVE_FALLBACK_ANSWER_SUFFIX, + NATIVE_FALLBACK_COUNTS_FIELD, + NATIVE_FALLBACK_DEFERRAL_STAGES, + NATIVE_FALLBACK_DEFERRAL_UNKNOWN_STAGE, + NATIVE_FALLBACK_LIST_HEADER, + NATIVE_FALLBACK_MAX_COUNTS_FIELD, + NATIVE_FALLBACK_MODE_UPDATE, + NATIVE_FALLBACK_PROJECT_CORPUS, + NATIVE_FALLBACK_SITE_SEPARATOR, +) +from scripts.compiler_differential.models import ( + AllowList, + FallbackGateRequest, + ProjectComparison, + RecordedRun, +) +from scripts.compiler_differential.types import FallbackKey + + +def native_fallback_gate( + *, request: FallbackGateRequest | None, comparisons: list[ProjectComparison] +) -> tuple[str, ...]: + """Check the run against the allow-list, or rewrite it; print and return every problem.""" + + if request is None: + return () + observed: dict[FallbackKey, dict[str, int]] = observed_fallbacks( + comparisons=comparisons, engines=request.run.engines + ) + if request.mode == NATIVE_FALLBACK_MODE_UPDATE: + write_allow_list(path=request.allow_list, observed=observed, run=request.run) + print(f"Native fallback allow-list rewritten: {request.allow_list}") + return () + problems: list[str] = fallback_problems( + observed=observed, allowed=read_allow_list(request.allow_list), run=request.run + ) + for problem in problems: + print(f"Native fallback allow-list: {problem}") + return tuple(problems) + + +def observed_fallbacks( + *, comparisons: list[ProjectComparison], engines: tuple[str, ...] +) -> dict[FallbackKey, dict[str, int]]: + """Sum every engine's fallback and analysis deferral records by entry and corpus.""" + + counts: Counter[tuple[FallbackKey, str]] = Counter() + for comparison in comparisons: + corpus: str = comparison.project.split("/", 1)[0] + for engine, records in zip(engines, comparison.records or (), strict=False): + for (site, kind), count in records.fallbacks.items(): + stage: str = site.split(NATIVE_FALLBACK_SITE_SEPARATOR, 1)[0] + counts[((engine, stage, site, kind), corpus)] += count + for (kind, site), count in records.deferrals.items(): + stage = NATIVE_FALLBACK_DEFERRAL_STAGES.get( + site, NATIVE_FALLBACK_DEFERRAL_UNKNOWN_STAGE + ) + counts[((engine, stage, site, kind), corpus)] += count + observed: dict[FallbackKey, dict[str, int]] = {} + for (key, corpus), count in sorted(counts.items()): + observed.setdefault(key, {})[corpus] = count + return observed + + +def read_allow_list(path: Path) -> AllowList: + """Parse the allow-list file; a missing file allows nothing.""" + + if not path.is_file(): + return AllowList(seed_start=0, seeds=0, counts={}, max_counts={}) + document: dict[str, object] = tomllib.loads(path.read_text(encoding="utf-8")) + counts: dict[FallbackKey, dict[str, int]] = {} + max_counts: dict[FallbackKey, dict[str, int]] = {} + entries: object = document.get("entry", []) + for entry in entries if isinstance(entries, list) else []: + key: FallbackKey = ( + str(entry["engine"]), + str(entry["stage"]), + str(entry["site"]), + str(entry["kind"]), + ) + bounded: bool = NATIVE_FALLBACK_MAX_COUNTS_FIELD in entry + field: str = NATIVE_FALLBACK_MAX_COUNTS_FIELD if bounded else NATIVE_FALLBACK_COUNTS_FIELD + target: dict[FallbackKey, dict[str, int]] = max_counts if bounded else counts + target[key] = {str(name): int(value) for name, value in entry[field].items()} + return AllowList( + seed_start=int(str(document.get("seed_start", 0))), + seeds=int(str(document.get("seeds", 0))), + counts=counts, + max_counts=max_counts, + ) + + +def fallback_problems( + *, observed: dict[FallbackKey, dict[str, int]], allowed: AllowList, run: RecordedRun +) -> list[str]: + """Every way the run's records differ from the allow-list, as instructions to the author.""" + + if CORPUS_SEEDS in run.corpora and (run.seed_start, run.seeds) != ( + allowed.seed_start, + allowed.seeds, + ): + return [ + f"the allow-list holds counts for --seed-start {allowed.seed_start} --seeds " + f"{allowed.seeds}; this run used --seed-start {run.seed_start} --seeds {run.seeds}" + ] + corpora: frozenset[str] = _corpus_prefixes(run.corpora) + observed_answers: Counter[tuple[str, str, str]] = _answer_totals(observed) + allowed_answers: Counter[tuple[str, str, str]] = _answer_totals( + {**allowed.counts, **allowed.max_counts} + ) + problems: list[str] = [] + for key in sorted({*allowed.counts, *allowed.max_counts, *observed}): + if key[0] not in run.engines: + continue + actual: dict[str, int] = observed.get(key, {}) + exact: dict[str, int] | None = allowed.counts.get(key) + bound: dict[str, int] | None = allowed.max_counts.get(key) + for corpus in sorted({*actual, *(exact or {}), *(bound or {})} & corpora): + problem: str | None = _corpus_problem( + label=_label(key=key, corpus=corpus), + answer=key[2].endswith(NATIVE_FALLBACK_ANSWER_SUFFIX), + actual=actual.get(corpus, 0), + exact=None if exact is None else exact.get(corpus, 0), + bound=None if bound is None else bound.get(corpus, 0), + answers_rose=observed_answers[(key[0], key[1], corpus)] + > allowed_answers[(key[0], key[1], corpus)], + ) + if problem is not None: + problems.append(problem) + return problems + + +def write_allow_list( + *, path: Path, observed: dict[FallbackKey, dict[str, int]], run: RecordedRun +) -> None: + """Record the run's counts, keeping entries for engines and corpora this run did not cover.""" + + previous: AllowList = read_allow_list(path) + covered: frozenset[str] = _corpus_prefixes(run.corpora) + counts: dict[FallbackKey, dict[str, int]] = {} + for key, by_corpus in previous.counts.items(): + kept: dict[str, int] = { + corpus: count + for corpus, count in by_corpus.items() + if key[0] not in run.engines or corpus not in covered + } + if kept: + counts[key] = kept + for key, by_corpus in observed.items(): + if key[0] in run.engines and key not in previous.max_counts: + counts[key] = {**counts.get(key, {}), **by_corpus} + entries: list[tuple[FallbackKey, str, dict[str, int]]] = [ + *((key, NATIVE_FALLBACK_COUNTS_FIELD, values) for key, values in counts.items()), + *( + (key, NATIVE_FALLBACK_MAX_COUNTS_FIELD, values) + for key, values in previous.max_counts.items() + ), + ] + seeded: bool = CORPUS_SEEDS in run.corpora + lines: list[str] = [ + NATIVE_FALLBACK_LIST_HEADER, + f"seed_start = {run.seed_start if seeded else previous.seed_start}", + f"seeds = {run.seeds if seeded else previous.seeds}", + ] + for (engine, stage, site, kind), field, values in sorted(entries): + inline: str = ", ".join(f"{corpus} = {count}" for corpus, count in sorted(values.items())) + lines.extend( + ( + "", + "[[entry]]", + f'engine = "{engine}"', + f'stage = "{stage}"', + f'site = "{site}"', + f'kind = "{kind}"', + f"{field} = {{ {inline} }}", + ) + ) + _ = path.write_text("\n".join(lines) + "\n", encoding="utf-8") + + +def _corpus_problem( + *, + label: str, + answer: bool, + actual: int, + exact: int | None, + bound: int | None, + answers_rose: bool, +) -> str | None: + if answer and exact is None and bound is None: + return f"{label}: native answered {actual}, not on the allow-list; record it" + if answer and actual == 0: + return ( + f"{label}: native no longer answers here, so this work now runs in Python; " + "restore the native path, or record the change with a reason" + ) + if exact is None and bound is None: + return f"{label}: {actual} not on the allow-list; port it or list it with a reason" + if actual == 0 and not answers_rose: + return ( + f"{label}: fallback disappeared but native answers did not appear; the stage may be " + "switched off. A port that removes a fallback must report native answers for the " + "work it now does" + ) + if actual == 0: + return f"{label}: listed but no longer occurs; remove it from the allow-list" + if bound is not None: + return None if actual <= bound else f"{label}: {actual} exceeds the allowed {bound}" + if actual != exact: + return f"{label}: {actual} where the allow-list expects {exact}; update the count" + return None + + +def _answer_totals( + entries: dict[FallbackKey, dict[str, int]], +) -> Counter[tuple[str, str, str]]: + """Native answer counts summed by engine, stage and corpus.""" + + totals: Counter[tuple[str, str, str]] = Counter() + for (engine, stage, site, _), by_corpus in entries.items(): + for corpus, count in by_corpus.items(): + totals[(engine, stage, corpus)] += count * site.endswith(NATIVE_FALLBACK_ANSWER_SUFFIX) + return totals + + +def _label(*, key: FallbackKey, corpus: str) -> str: + engine, stage, site, kind = key + return f"{engine} {stage} {site} {kind} ({corpus})" + + +def _corpus_prefixes(corpora: tuple[str, ...]) -> frozenset[str]: + """Project-name prefixes of the selected corpora (`seeds` names projects `seed/...`).""" + + return frozenset( + {*(corpus.removesuffix("s") for corpus in corpora), NATIVE_FALLBACK_PROJECT_CORPUS} + ) diff --git a/scripts/compiler_differential/_helpers/running/records.py b/scripts/compiler_differential/_helpers/running/records.py index b1ab9e0145..9cecee24f2 100644 --- a/scripts/compiler_differential/_helpers/running/records.py +++ b/scripts/compiler_differential/_helpers/running/records.py @@ -1,4 +1,4 @@ -"""Read the debug analysis records one engine's processes wrote: wheel call sites and deferrals.""" +"""Read the debug records one engine's processes wrote: wheel sites, deferrals and fallbacks.""" from __future__ import annotations @@ -10,16 +10,18 @@ from scripts.compiler_differential._helpers.comparing.compare import as_json_object from scripts.compiler_differential.constants import ( ANALYSIS_DEFERRAL_RECORD_PREFIX, + NATIVE_FALLBACK_RECORD_PREFIX, WHEEL_SITE_RECORD_PREFIX, ) from scripts.compiler_differential.models import AnalysisRecords, ProjectComparison def read_analysis_records(root: Path) -> AnalysisRecords: - """Sum every process's wheel-site counts and `{"kind", "site"}` deferral lines below `root`.""" + """Sum every process's wheel-site, deferral and native-fallback records below `root`.""" sites: Counter[tuple[str, str]] = Counter() deferrals: Counter[tuple[str, str]] = Counter() + fallbacks: Counter[tuple[str, str]] = Counter() for path in sorted(root.rglob(f"{WHEEL_SITE_RECORD_PREFIX}*.json")) if root.is_dir() else (): payload: dict[str, object] = as_json_object(json.loads(path.read_text("utf-8"))) or {} rows: object = payload.get("calls") @@ -32,18 +34,29 @@ def read_analysis_records(root: Path) -> AnalysisRecords: for line in path.read_text("utf-8").splitlines(): record: dict[str, object] = as_json_object(json.loads(line)) or {} deferrals[(str(record.get("kind")), str(record.get("site")))] += 1 - return AnalysisRecords(wheel_sites=dict(sites), deferrals=dict(deferrals)) + for path in ( + sorted(root.rglob(f"{NATIVE_FALLBACK_RECORD_PREFIX}*.json")) if root.is_dir() else () + ): + payload = as_json_object(json.loads(path.read_text("utf-8"))) or {} + rows = payload.get("fallbacks") + for row in rows if isinstance(rows, list) else (): + site, kind, count = cast(list[object], row) + fallbacks[(str(site), str(kind))] += int(str(count)) + return AnalysisRecords( + wheel_sites=dict(sites), deferrals=dict(deferrals), fallbacks=dict(fallbacks) + ) def wheel_site_report( *, comparisons: list[ProjectComparison], engines: tuple[str, str] ) -> dict[str, object]: - """Return wheel calls per engine, site and API, split by corpus, plus deferral counts.""" + """Return wheel calls, deferrals and native fallbacks per engine, split by corpus.""" report: dict[str, object] = {} for side, engine in enumerate(engines): sites: dict[str, dict[str, int]] = {} deferrals: dict[str, dict[str, int]] = {} + fallbacks: dict[str, dict[str, int]] = {} for comparison in comparisons: records: AnalysisRecords | None = ( comparison.records[side] if comparison.records else None @@ -57,15 +70,19 @@ def wheel_site_report( for (kind, site), count in records.deferrals.items(): by_corpus = deferrals.setdefault(f"{kind} {site}", {}) by_corpus[corpus] = by_corpus.get(corpus, 0) + count + for (site, kind), count in records.fallbacks.items(): + by_corpus = fallbacks.setdefault(f"{site} {kind}", {}) + by_corpus[corpus] = by_corpus.get(corpus, 0) + count report[engine] = { "wheel_sites": dict(sorted(sites.items())), "deferrals": dict(sorted(deferrals.items())), + "native_fallbacks": dict(sorted(fallbacks.items())), } return report def format_wheel_site_report(report: dict[str, object]) -> str: - """Render the wheel-site and deferral counts for the run log; nothing here gates.""" + """Render the wheel-site, deferral and fallback counts for the run log; nothing here gates.""" lines: list[str] = [] for engine, raw in report.items(): @@ -73,6 +90,7 @@ def format_wheel_site_report(report: dict[str, object]) -> str: for label, key in ( ("Polyglot wheel calls", "wheel_sites"), ("Analysis deferrals", "deferrals"), + ("Native-to-Python fallbacks", "native_fallbacks"), ): counts: dict[str, object] = as_json_object(entry.get(key)) or {} lines.append(f"{label} ({engine}): {'none recorded' if not counts else ''}".rstrip()) @@ -82,3 +100,14 @@ def format_wheel_site_report(report: dict[str, object]) -> str: total: int = sum(int(str(count)) for count in corpora.values()) lines.append(f" {total:>7} {name} ({split})") return "\n".join(lines) + + +def write_wheel_site_report( + *, path: Path, comparisons: list[ProjectComparison], engines: tuple[str, str] +) -> None: + """Write the wheel-site, deferral and fallback counts to `path` as JSON and print them.""" + + report: dict[str, object] = wheel_site_report(comparisons=comparisons, engines=engines) + path.parent.mkdir(parents=True, exist_ok=True) + _ = path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8") + print(format_wheel_site_report(report)) diff --git a/scripts/compiler_differential/_helpers/running/report.py b/scripts/compiler_differential/_helpers/running/report.py index ba7d523fbb..e227a7a18b 100644 --- a/scripts/compiler_differential/_helpers/running/report.py +++ b/scripts/compiler_differential/_helpers/running/report.py @@ -4,7 +4,9 @@ from scripts.compiler_differential.constants import ( ANALYSIS_INDIRECT_KINDS, + BASELINES_HINT, CONFIG_ONLY_KINDS, + GOLDEN_LABEL, RENDER_CONFIG_ONLY_KINDS, RENDER_INDIRECT_KINDS, ) @@ -31,15 +33,16 @@ def format_summary( engines: tuple[str, str], seconds: float, missing_coverage: dict[str, tuple[str, ...]] | None = None, + gate_failures: tuple[str, ...] = (), ) -> str: - """Summarize the run; any difference or missing coverage, keyed by stage, reports FAILED.""" + """Summarize the run; a difference, missing coverage or gate failure reports FAILED.""" differing: list[ProjectComparison] = [item for item in comparisons if item.differences] gaps: dict[str, tuple[str, ...]] = { stage: kinds for stage, kinds in (missing_coverage or {}).items() if kinds } left_engine, right_engine = engines - if not differing and not gaps: + if not differing and not gaps and not gate_failures: return ( f"Compiler differential passed: {len(comparisons)} projects identical " f"({left_engine} vs {right_engine}) in {seconds:.1f}s" @@ -54,9 +57,17 @@ def format_summary( lines.extend( f"Required {stage} coverage missing: {', '.join(kinds)}" for stage, kinds in gaps.items() ) + if gate_failures: + lines.append(f"Native fallback allow-list: {len(gate_failures)} problems (listed above)") + if gate_failures or any(_golden_differs(comparison) for comparison in differing): + lines.append(BASELINES_HINT) return "\n".join(lines) +def _golden_differs(comparison: ProjectComparison) -> bool: + return any(GOLDEN_LABEL in (difference.labels or ()) for difference in comparison.differences) + + def format_discovery_coverage(*, covered: frozenset[str], required: tuple[str, ...]) -> str: """Report how many required discovery input kinds the seed corpus exercised.""" diff --git a/scripts/compiler_differential/_helpers/running/run.py b/scripts/compiler_differential/_helpers/running/run.py index b1661e72b0..5aac42cf4e 100644 --- a/scripts/compiler_differential/_helpers/running/run.py +++ b/scripts/compiler_differential/_helpers/running/run.py @@ -14,7 +14,9 @@ from scripts.compiler_differential.models import ( CorpusProject, DifferentialOptions, + FallbackGateRequest, ProjectComparison, + RecordedRun, ) @@ -31,8 +33,29 @@ def differential_options(*, args: argparse.Namespace, work_dir: Path) -> Differe require_discovery_coverage=args.require_discovery_coverage, require_render_coverage=args.require_render_coverage, require_analysis_coverage=args.require_analysis_coverage, - analysis_records=args.wheel_site_report is not None, + analysis_records=args.wheel_site_report is not None or args.native_fallbacks is not None, evidence_dir=args.evidence_dir, + golden_mode=args.goldens, + golden_dir=args.golden_dir, + ) + + +def fallback_gate_request( + *, args: argparse.Namespace, engines: tuple[str, str] +) -> FallbackGateRequest | None: + """Return the run's fallback allow-list gate, or None when it is off.""" + + if args.native_fallbacks is None: + return None + return FallbackGateRequest( + mode=args.native_fallbacks, + allow_list=args.native_fallback_list, + run=RecordedRun( + engines=engines, + corpora=tuple(args.corpus), + seed_start=args.seed_start, + seeds=args.seeds, + ), ) diff --git a/scripts/compiler_differential/classes/analysis_features.py b/scripts/compiler_differential/classes/analysis_features.py index e45a65edaa..9240dc67dc 100644 --- a/scripts/compiler_differential/classes/analysis_features.py +++ b/scripts/compiler_differential/classes/analysis_features.py @@ -331,6 +331,28 @@ def _python_sql(self) -> None: def _analysis_modes(self) -> None: self._features.add("analysis_modes") base: ModelPlan = self._base() + self._model( + name=f"cte_facts_{base.name}", + description=f"Contracted CTE reads of {base.name}", + header=( + " contract enforced,\n columns (\n" + + "".join( + f' {column} (description "Recovered {column}"),\n' + for column in ("id", "amount", "kind", "status") + ) + + " ),\n" + ), + body=( + "WITH base AS (\n" + " SELECT id, CAST(amount AS DECIMAL(12, 2)) AS amount, 'event' AS kind,\n" + " COALESCE(status, 'unknown') AS status\n" + f' FROM __ref("{base.name}")\n' + " WHERE id IS NOT NULL\n" + ")\n" + "SELECT id + 0 AS id, amount, UPPER(kind) AS kind, UPPER(status) AS status\n" + "FROM base\n" + ), + ) self.commands = tuple( _selected_command(label=label, arguments=arguments, model=base.name) for label, arguments in GENERATOR_ANALYSIS_MODE_COMMANDS diff --git a/scripts/compiler_differential/constants.py b/scripts/compiler_differential/constants.py index 008e546c06..1ee5525a4d 100644 --- a/scripts/compiler_differential/constants.py +++ b/scripts/compiler_differential/constants.py @@ -10,7 +10,58 @@ ANALYSIS_RECORD_ENV_VAR: str = "SQLBUILD_ANALYSIS_RECORD_DIR" WHEEL_SITE_RECORD_PREFIX: str = "polyglot-sites-" ANALYSIS_DEFERRAL_RECORD_PREFIX: str = "analysis-deferrals-" +NATIVE_FALLBACK_RECORD_PREFIX: str = "native-fallbacks-" +NATIVE_FALLBACK_LIST: str = "scripts/compiler_differential/native_fallbacks.toml" +NATIVE_FALLBACK_MODE_UPDATE: str = "update" +NATIVE_FALLBACK_MODES: tuple[str, ...] = ("check", NATIVE_FALLBACK_MODE_UPDATE) +NATIVE_FALLBACK_SITE_SEPARATOR: str = "." +NATIVE_FALLBACK_ANSWER_SUFFIX: str = ".native" +BASELINES_HINT: str = ( + "Intended? Run `make compiler-baselines` and commit the changes to " + "scripts/compiler_differential/native_fallbacks.toml and tests/goldens/compiler, with a " + "reason in the PR body for every added entry, higher fallback count or changed golden." +) +NATIVE_FALLBACK_MAX_COUNTS_FIELD: str = "max_counts" +NATIVE_FALLBACK_COUNTS_FIELD: str = "counts" +NATIVE_FALLBACK_PROJECT_CORPUS: str = "project" +NATIVE_FALLBACK_DEFERRAL_STAGES: dict[str, str] = { + "analysis_session": "model_analysis", + "fast_columns.py": "lineage_facts", + "type_recovery.py": "semantic_checks", + "recovery.py": "semantic_checks", + "metadata_validation.py": "semantic_checks", + "contracts/columns.py": "contracts", + "contracts/promotion.py": "contracts", +} +NATIVE_FALLBACK_DEFERRAL_UNKNOWN_STAGE: str = "analysis" +NATIVE_FALLBACK_LIST_HEADER: str = ( + "# Every native-to-Python fallback and preview analysis deferral the CI corpus may still\n" + "# reach, with its exact count per corpus. `--native-fallbacks check` fails on anything new,\n" + "# changed or gone. Ports delete their entries; see scripts/compiler_differential/README.md.\n" + "# The corpus does not reach type normalization (type_system): its callers are the planner,\n" + "# the executor and the preview fallbacks, so test_native_type_parity.py covers that stage." +) RECORDS_DIRECTORY: str = "records" +GOLDEN_DIRECTORY: str = "tests/goldens/compiler" +GOLDEN_MODE_CHECK: str = "check" +GOLDEN_MODE_UPDATE: str = "update" +GOLDEN_MODES: tuple[str, ...] = (GOLDEN_MODE_CHECK, GOLDEN_MODE_UPDATE) +GOLDEN_CORPUS_PREFIXES: frozenset[str] = frozenset( + {"fixture", "example", "seed", "failure", "project"} +) +GOLDEN_SEED_CORPUS: str = "seed" +GOLDEN_SEED_RANGE_FILE: str = "seed_range.toml" +GOLDEN_SUFFIX: str = ".json" +GOLDEN_LABEL: str = "golden" +GOLDEN_MANIFEST_DROPPED_KEYS: frozenset[str] = frozenset({"metadata", "child_map"}) +GOLDEN_MANIFEST_RESOURCE_SECTIONS: tuple[str, ...] = ("nodes", "sources", "macros") +GOLDEN_RESOURCE_DROPPED_FIELDS: frozenset[str] = frozenset( + {"raw_code", "compiled_code", "checksum", "created_at"} +) +GOLDEN_PATH_MASK: str = "" +GOLDEN_WORK_MASK: str = "" +GOLDEN_VERSION_MASK: str = "" +GOLDEN_MISSING_HINT: str = "no golden; record it with `make compiler-baselines`" ENGINE_NAMES: tuple[str, ...] = ("python", "native", "native-preview") DEFAULT_ENGINES: tuple[str, str] = ("python", "native-preview") SQB_ENTRY: str = "import sys; from sqlbuild.cli.entry.main.entry import main; sys.exit(main())" diff --git a/scripts/compiler_differential/main/differential.py b/scripts/compiler_differential/main/differential.py index c755a12f6f..2ac8f10ce0 100644 --- a/scripts/compiler_differential/main/differential.py +++ b/scripts/compiler_differential/main/differential.py @@ -3,7 +3,6 @@ from __future__ import annotations import argparse -import json import os import sys import tempfile @@ -13,11 +12,10 @@ from scripts.compiler_differential._helpers.coverage.analysis import required_analysis_kinds from scripts.compiler_differential._helpers.coverage.discovery import required_discovery_kinds from scripts.compiler_differential._helpers.coverage.render import required_render_kinds +from scripts.compiler_differential._helpers.goldens.goldens import write_golden_seed_range +from scripts.compiler_differential._helpers.running.native_fallbacks import native_fallback_gate from scripts.compiler_differential._helpers.running.options import parse_expected_outcome -from scripts.compiler_differential._helpers.running.records import ( - format_wheel_site_report, - wheel_site_report, -) +from scripts.compiler_differential._helpers.running.records import write_wheel_site_report from scripts.compiler_differential._helpers.running.report import ( format_analysis_coverage, format_discovery_coverage, @@ -27,6 +25,7 @@ from scripts.compiler_differential._helpers.running.run import ( compare_corpus, differential_options, + fallback_gate_request, selected_corpus, ) from scripts.compiler_differential.constants import ( @@ -37,6 +36,11 @@ DEFAULT_SEED_COUNT, ENGINE_NAMES, EXPECT_SUCCESS, + GOLDEN_DIRECTORY, + GOLDEN_MODE_UPDATE, + GOLDEN_MODES, + NATIVE_FALLBACK_LIST, + NATIVE_FALLBACK_MODES, PER_PULL_REQUEST_CORPORA, ) from scripts.compiler_differential.models import DifferentialOptions, ProjectComparison @@ -60,25 +64,30 @@ def run_compiler_differential(argv: list[str] | None = None) -> int: else {} ) if args.wheel_site_report is not None: - report: dict[str, object] = wheel_site_report( - comparisons=comparisons, engines=options.engines + write_wheel_site_report( + path=args.wheel_site_report, comparisons=comparisons, engines=options.engines ) - args.wheel_site_report.parent.mkdir(parents=True, exist_ok=True) - _ = args.wheel_site_report.write_text( - json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8" + if args.goldens == GOLDEN_MODE_UPDATE and CORPUS_SEEDS in args.corpus: + write_golden_seed_range( + golden_dir=args.golden_dir, seed_start=args.seed_start, seeds=args.seeds ) - print(format_wheel_site_report(report)) + fallback_failures: tuple[str, ...] = native_fallback_gate( + request=fallback_gate_request(args=args, engines=options.engines), + comparisons=comparisons, + ) print( format_summary( comparisons=comparisons, engines=options.engines, seconds=time.monotonic() - started, missing_coverage=missing_coverage, + gate_failures=fallback_failures, ) ) return ( 1 if any(missing_coverage.values()) + or fallback_failures or any(comparison.differences for comparison in comparisons) else 0 ) @@ -179,6 +188,37 @@ def _parse_args(argv: list[str] | None) -> argparse.Namespace: "process, print them and write them to PATH as JSON (reported, never gated)" ), ) + parser.add_argument( + "--native-fallbacks", + choices=NATIVE_FALLBACK_MODES, + default=None, + help=( + "record native-to-Python fallbacks and analysis deferrals in every engine process and " + "check them against the allow-list (new, changed or vanished entries fail), or " + "rewrite the list from this run" + ), + ) + parser.add_argument( + "--native-fallback-list", + type=Path, + default=None, + help=f"fallback allow-list file (default: {NATIVE_FALLBACK_LIST} in the repository)", + ) + parser.add_argument( + "--goldens", + choices=GOLDEN_MODES, + default=None, + help=( + "check every engine's fixture, example, seed and failure outputs against the golden " + "files, or rewrite them from the first (oracle) engine" + ), + ) + parser.add_argument( + "--golden-dir", + type=Path, + default=None, + help=f"golden output directory (default: {GOLDEN_DIRECTORY} in the repository)", + ) parser.add_argument( "--engine-env", action="append", @@ -196,6 +236,11 @@ def _parse_args(argv: list[str] | None) -> argparse.Namespace: ) parser.add_argument("--python", type=Path, default=Path(sys.executable)) args: argparse.Namespace = parser.parse_args(argv) + repo_root: Path = Path(__file__).resolve().parents[3] + if args.golden_dir is None: + args.golden_dir = repo_root / GOLDEN_DIRECTORY + if args.native_fallback_list is None: + args.native_fallback_list = repo_root / NATIVE_FALLBACK_LIST for flag, required in ( ("--require-discovery-coverage", args.require_discovery_coverage), ("--require-render-coverage", args.require_render_coverage), diff --git a/scripts/compiler_differential/models.py b/scripts/compiler_differential/models.py index 8de8914cb7..d47a9f3212 100644 --- a/scripts/compiler_differential/models.py +++ b/scripts/compiler_differential/models.py @@ -6,6 +6,8 @@ from dataclasses import dataclass, field from pathlib import Path +from scripts.compiler_differential.types import FallbackKey + @dataclass(frozen=True) class DifferentialCommand: @@ -51,10 +53,11 @@ class CommandOutcome: @dataclass(frozen=True) class AnalysisRecords: - """Wheel calls by `(site, api)` and analysis deferrals by `(kind, site)` for one run.""" + """Wheel calls by `(site, api)`, deferrals by `(kind, site)`, fallbacks by `(site, kind)`.""" wheel_sites: dict[tuple[str, str], int] = field(default_factory=dict) deferrals: dict[tuple[str, str], int] = field(default_factory=dict) + fallbacks: dict[tuple[str, str], int] = field(default_factory=dict) @dataclass(frozen=True) @@ -119,6 +122,8 @@ class DifferentialOptions: require_analysis_coverage: bool = False analysis_records: bool = False evidence_dir: Path | None = None + golden_mode: str | None = None + golden_dir: Path | None = None @dataclass(frozen=True) @@ -206,3 +211,32 @@ def first_error(self) -> str | None: """Return the first reported error code, if any.""" return self.errors[0] if self.errors else None + + +@dataclass(frozen=True) +class RecordedRun: + """The engines, corpora and seed range one harness run covered.""" + + engines: tuple[str, ...] + corpora: tuple[str, ...] + seed_start: int + seeds: int + + +@dataclass(frozen=True) +class AllowList: + """Allowed counts by `(engine, stage, site, kind)` and corpus, and the seeds they hold for.""" + + seed_start: int + seeds: int + counts: dict[FallbackKey, dict[str, int]] + max_counts: dict[FallbackKey, dict[str, int]] + + +@dataclass(frozen=True) +class FallbackGateRequest: + """One run's fallback gate: check or rewrite `allow_list` from what the engines recorded.""" + + mode: str + allow_list: Path + run: RecordedRun diff --git a/scripts/compiler_differential/native_fallbacks.toml b/scripts/compiler_differential/native_fallbacks.toml new file mode 100644 index 0000000000..6d596e22db --- /dev/null +++ b/scripts/compiler_differential/native_fallbacks.toml @@ -0,0 +1,665 @@ +# Every native-to-Python fallback and preview analysis deferral the CI corpus may still +# reach, with its exact count per corpus. `--native-fallbacks check` fails on anything new, +# changed or gone. Ports delete their entries; see scripts/compiler_differential/README.md. +# The corpus does not reach type normalization (type_system): its callers are the planner, +# the executor and the preview fallbacks, so test_native_type_parity.py covers that stage. +seed_start = 0 +seeds = 12 + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.audit_rendering" +kind = "deferred" +counts = { seed = 16 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "audit_renderings" +counts = { example = 120, failure = 10, fixture = 112, seed = 354 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "cursor_intrinsic_rejections" +counts = { example = 160, failure = 177, fixture = 156, seed = 961 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "function_headers" +counts = { example = 8, failure = 7, fixture = 12, seed = 102 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "omitted_select_scans" +counts = { example = 24, failure = 22, fixture = 32, seed = 193 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "scenario_ctes" +counts = { example = 8, failure = 1, fixture = 12, seed = 37 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.native" +kind = "seed_pairs" +counts = { example = 8, fixture = 4, seed = 26 } + +[[entry]] +engine = "native" +stage = "attachments" +site = "attachments.scenario_independence" +kind = "deferred" +counts = { failure = 1 } + +[[entry]] +engine = "native" +stage = "declaration_files" +site = "declaration_files.native" +kind = "failed_files" +counts = { failure = 9 } + +[[entry]] +engine = "native" +stage = "declaration_files" +site = "declaration_files.native" +kind = "parsed_files" +counts = { example = 32, failure = 69, fixture = 20, seed = 799 } + +[[entry]] +engine = "native" +stage = "declaration_files" +site = "declaration_files.native" +kind = "seed_files" +counts = { example = 8, failure = 3, fixture = 4, seed = 43 } + +[[entry]] +engine = "native" +stage = "declaration_scopes" +site = "declaration_scopes.native" +kind = "scope_indexes" +counts = { example = 12, failure = 229, fixture = 12, seed = 44 } + +[[entry]] +engine = "native" +stage = "declaration_scopes" +site = "declaration_scopes.rebind_lookup" +kind = "deferred" +counts = { failure = 1, seed = 802 } + +[[entry]] +engine = "native" +stage = "declaration_scopes" +site = "declaration_scopes.relationship_ctes" +kind = "expected_names" +counts = { example = 1, failure = 3, fixture = 3, seed = 26 } + +[[entry]] +engine = "native" +stage = "discovery" +site = "discovery.native" +kind = "model_file_listings" +counts = { example = 12, failure = 294, fixture = 12, seed = 50 } + +[[entry]] +engine = "native" +stage = "macro_call_store" +site = "macro_call_store.native" +kind = "served_calls" +counts = { example = 18, fixture = 15, seed = 192 } + +[[entry]] +engine = "native" +stage = "macro_calls" +site = "macro_calls.arguments" +kind = "deferred" +counts = { example = 6, failure = 14, fixture = 5, seed = 484 } + +[[entry]] +engine = "native" +stage = "macro_calls" +site = "macro_calls.native" +kind = "bridged_calls" +counts = { example = 32, failure = 9, fixture = 28, seed = 466 } + +[[entry]] +engine = "native" +stage = "macro_calls" +site = "macro_calls.resolution" +kind = "deferred" +counts = { failure = 4, seed = 3 } + +[[entry]] +engine = "native" +stage = "macro_calls" +site = "macro_calls.unbridged_expansion" +kind = "macro_mocks" +counts = { seed = 238 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.header_metadata" +kind = "stale" +counts = { seed = 19 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.header_metadata" +kind = "unsupported" +counts = { failure = 1 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.native" +kind = "config_builds" +counts = { example = 56, failure = 310, fixture = 64, seed = 914 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.native" +kind = "validations" +counts = { example = 56, failure = 383, fixture = 60, seed = 1115 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "api" +counts = { example = 16, failure = 2, seed = 36 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "config" +counts = { example = 12, failure = 119, fixture = 8, seed = 36 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "connection" +counts = { example = 18, failure = 121, fixture = 9, seed = 63 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "effective_vars" +counts = { example = 29, failure = 244, fixture = 15, seed = 121 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "seed_target" +counts = { example = 8, seed = 30 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.python_templates" +kind = "source_target" +counts = { example = 8, seed = 23 } + +[[entry]] +engine = "native" +stage = "model_config" +site = "model_config.validators" +kind = "deferred" +counts = { failure = 2, fixture = 4, seed = 3 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.cursor_intrinsic_validation" +kind = "deferred" +counts = { example = 56, failure = 413, fixture = 64, seed = 1124 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.declaration_context" +kind = "no_resource" +counts = { example = 24, failure = 9, fixture = 20, seed = 245 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.declaration_references" +kind = "after_variables" +counts = { seed = 3 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.native" +kind = "declaration_expansions" +counts = { example = 56, failure = 424, fixture = 64, seed = 1124 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.native" +kind = "variable_substitutions" +counts = { example = 56, failure = 466, fixture = 72, seed = 1181 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.sql_variables" +kind = "deferred" +counts = { failure = 3, seed = 195 } + +[[entry]] +engine = "native" +stage = "model_loop" +site = "model_loop.sql_variables" +kind = "error" +counts = { failure = 2 } + +[[entry]] +engine = "native" +stage = "reference_extraction" +site = "reference_extraction.native" +kind = "reference_scans" +counts = { example = 250, failure = 479, fixture = 249, seed = 1532 } + +[[entry]] +engine = "native-preview" +stage = "analysis" +site = "project_assembly" +kind = "syntax_error" +counts = { failure = 3 } + +[[entry]] +engine = "native-preview" +stage = "analysis" +site = "project_assembly" +kind = "unsupported_dialect" +counts = { failure = 1 } + +[[entry]] +engine = "native-preview" +stage = "analysis" +site = "sql_test_assembly" +kind = "macro_mocks" +counts = { seed = 29 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.audit_rendering" +kind = "deferred" +counts = { seed = 16 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "audit_renderings" +counts = { example = 120, failure = 10, fixture = 112, seed = 354 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "cursor_intrinsic_rejections" +counts = { example = 160, failure = 177, fixture = 156, seed = 961 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "function_headers" +counts = { example = 8, failure = 7, fixture = 12, seed = 102 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "omitted_select_scans" +counts = { example = 24, failure = 22, fixture = 32, seed = 193 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "scenario_ctes" +counts = { example = 8, failure = 1, fixture = 12, seed = 37 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.native" +kind = "seed_pairs" +counts = { example = 8, fixture = 4, seed = 26 } + +[[entry]] +engine = "native-preview" +stage = "attachments" +site = "attachments.scenario_independence" +kind = "deferred" +counts = { failure = 1 } + +[[entry]] +engine = "native-preview" +stage = "contracts" +site = "contracts.native" +kind = "contract_validations" +counts = { example = 9, failure = 113, fixture = 6, seed = 25 } + +[[entry]] +engine = "native-preview" +stage = "contracts" +site = "contracts.native" +kind = "promotion_checks" +counts = { example = 12, failure = 113, fixture = 8, seed = 33 } + +[[entry]] +engine = "native-preview" +stage = "declaration_files" +site = "declaration_files.native" +kind = "failed_files" +counts = { failure = 9 } + +[[entry]] +engine = "native-preview" +stage = "declaration_files" +site = "declaration_files.native" +kind = "parsed_files" +counts = { example = 32, failure = 69, fixture = 20, seed = 799 } + +[[entry]] +engine = "native-preview" +stage = "declaration_files" +site = "declaration_files.native" +kind = "seed_files" +counts = { example = 8, failure = 3, fixture = 4, seed = 43 } + +[[entry]] +engine = "native-preview" +stage = "declaration_scopes" +site = "declaration_scopes.native" +kind = "scope_indexes" +counts = { example = 12, failure = 229, fixture = 12, seed = 44 } + +[[entry]] +engine = "native-preview" +stage = "declaration_scopes" +site = "declaration_scopes.rebind_lookup" +kind = "deferred" +counts = { failure = 1, seed = 802 } + +[[entry]] +engine = "native-preview" +stage = "declaration_scopes" +site = "declaration_scopes.relationship_ctes" +kind = "expected_names" +counts = { example = 1, failure = 3, fixture = 3, seed = 26 } + +[[entry]] +engine = "native-preview" +stage = "discovery" +site = "discovery.native" +kind = "model_file_listings" +counts = { example = 12, failure = 294, fixture = 12, seed = 50 } + +[[entry]] +engine = "native-preview" +stage = "lineage_facts" +site = "lineage_facts.native" +kind = "lineage_graphs" +counts = { example = 9, failure = 113, fixture = 6, seed = 22 } + +[[entry]] +engine = "native-preview" +stage = "macro_call_store" +site = "macro_call_store.native" +kind = "served_calls" +counts = { example = 18, fixture = 15, seed = 192 } + +[[entry]] +engine = "native-preview" +stage = "macro_calls" +site = "macro_calls.arguments" +kind = "deferred" +counts = { example = 6, failure = 14, fixture = 5, seed = 484 } + +[[entry]] +engine = "native-preview" +stage = "macro_calls" +site = "macro_calls.native" +kind = "bridged_calls" +counts = { example = 32, failure = 9, fixture = 28, seed = 466 } + +[[entry]] +engine = "native-preview" +stage = "macro_calls" +site = "macro_calls.resolution" +kind = "deferred" +counts = { failure = 4, seed = 3 } + +[[entry]] +engine = "native-preview" +stage = "macro_calls" +site = "macro_calls.unbridged_expansion" +kind = "macro_mocks" +counts = { seed = 238 } + +[[entry]] +engine = "native-preview" +stage = "model_analysis" +site = "analysis_session" +kind = "input_enrichment" +counts = { failure = 1 } + +[[entry]] +engine = "native-preview" +stage = "model_analysis" +site = "analysis_session" +kind = "legacy_analysis" +counts = { failure = 2, seed = 10 } + +[[entry]] +engine = "native-preview" +stage = "model_analysis" +site = "model_analysis.native" +kind = "dynamic_contract_proofs" +counts = { seed = 3 } + +[[entry]] +engine = "native-preview" +stage = "model_analysis" +site = "model_analysis.native" +kind = "expression_shapes" +counts = { example = 4, failure = 119, fixture = 4, seed = 100 } + +[[entry]] +engine = "native-preview" +stage = "model_analysis" +site = "model_analysis.native" +kind = "model_analyses" +counts = { example = 56, failure = 232, fixture = 52, seed = 698 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.header_metadata" +kind = "stale" +counts = { seed = 19 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.header_metadata" +kind = "unsupported" +counts = { failure = 1 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.native" +kind = "config_builds" +counts = { example = 56, failure = 310, fixture = 64, seed = 914 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.native" +kind = "validations" +counts = { example = 56, failure = 383, fixture = 60, seed = 1115 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.python_templates" +kind = "api" +counts = { example = 16, failure = 2, seed = 36 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.python_templates" +kind = "config" +counts = { example = 12, failure = 119, fixture = 8, seed = 36 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.python_templates" +kind = "connection" +counts = { example = 18, failure = 121, fixture = 9, seed = 63 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.python_templates" +kind = "effective_vars" +counts = { example = 29, failure = 244, fixture = 15, seed = 121 } + +[[entry]] +engine = "native-preview" +stage = "model_config" +site = "model_config.validators" +kind = "deferred" +counts = { failure = 2, fixture = 4, seed = 3 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.cursor_intrinsic_validation" +kind = "deferred" +counts = { example = 56, failure = 413, fixture = 64, seed = 1124 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.declaration_context" +kind = "no_resource" +counts = { example = 24, failure = 9, fixture = 20, seed = 245 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.declaration_references" +kind = "after_variables" +counts = { seed = 3 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.native" +kind = "declaration_expansions" +counts = { example = 56, failure = 424, fixture = 64, seed = 1124 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.native" +kind = "variable_substitutions" +counts = { example = 56, failure = 466, fixture = 72, seed = 1181 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.sql_variables" +kind = "deferred" +counts = { failure = 3, seed = 195 } + +[[entry]] +engine = "native-preview" +stage = "model_loop" +site = "model_loop.sql_variables" +kind = "error" +counts = { failure = 2 } + +[[entry]] +engine = "native-preview" +stage = "project_assembly" +site = "project_assembly.assembly" +kind = "deferred" +counts = { failure = 4 } + +[[entry]] +engine = "native-preview" +stage = "project_assembly" +site = "project_assembly.native" +kind = "project_assemblies" +counts = { example = 12, failure = 115, fixture = 8, seed = 36 } + +[[entry]] +engine = "native-preview" +stage = "reference_extraction" +site = "reference_extraction.native" +kind = "reference_scans" +counts = { example = 250, failure = 477, fixture = 249, seed = 1532 } + +[[entry]] +engine = "native-preview" +stage = "semantic_checks" +site = "semantic_checks.native" +kind = "semantic_completions" +counts = { example = 12, failure = 115, fixture = 8, seed = 36 } + +[[entry]] +engine = "native-preview" +stage = "sql_test_glue" +site = "sql_test_glue.assembly" +kind = "deferred" +counts = { seed = 29 } + +[[entry]] +engine = "native-preview" +stage = "sql_test_glue" +site = "sql_test_glue.native" +kind = "sql_test_assemblies" +counts = { example = 16, failure = 7, fixture = 20, seed = 143 } + +[[entry]] +engine = "native-preview" +stage = "sql_test_glue" +site = "sql_test_glue.native" +kind = "sql_test_plans" +counts = { example = 1, failure = 5, fixture = 1, seed = 9 } + +[[entry]] +engine = "python" +stage = "discovery" +site = "discovery.native" +kind = "model_file_listings" +counts = { example = 12, failure = 294, fixture = 12, seed = 50 } diff --git a/scripts/compiler_differential/types.py b/scripts/compiler_differential/types.py index 7ee809df54..8d7c289207 100644 --- a/scripts/compiler_differential/types.py +++ b/scripts/compiler_differential/types.py @@ -3,3 +3,5 @@ from collections.abc import Callable type NodeResolvers = tuple[Callable[[object], object], Callable[[object], object]] + +type FallbackKey = tuple[str, str, str, str] diff --git a/src/sqlbuild/_native.pyi b/src/sqlbuild/_native.pyi index 5d194a0bf1..5d5f96029c 100644 --- a/src/sqlbuild/_native.pyi +++ b/src/sqlbuild/_native.pyi @@ -4,10 +4,11 @@ from collections.abc import Sequence from typing import Any, TypedDict from sqlbuild.compiler.sql_test_glue.models import ( + NativeSqlTestAssemblyRequest, NativeSqlTestChainRequest, NativeSqlTestPlanningRequest, ) -from sqlbuild.compiler.sql_test_glue.types import NativeSqlTestPlanRow +from sqlbuild.compiler.sql_test_glue.types import NativeSqlTestAssemblyRow, NativeSqlTestPlanRow BUILD_IDENTITY: str @@ -349,7 +350,22 @@ def normalize_type( # Native analysis: model analysis session. type _AnalysisDiagnosticRow = tuple[str, str, int | None, int | None, int | None, int | None, str] +type _PivotContractRow = tuple[ + str, + tuple[ + bool, + list[tuple[str, str | None, str]], + list[tuple[str, str | None]], + list[str], + str | None, + bool, + ] + | None, +] + class NativeModelAnalysisSession: + @property + def fact_models(self) -> list[str]: ... def run( self, ) -> ( @@ -420,38 +436,43 @@ class NativeModelAnalysisSession: ] | None ): ... + def prove_dynamic_contracts( + self, models: list[tuple[str, list[tuple[str, str, str, str, str, str | None]]]], / + ) -> list[_PivotContractRow] | None: ... @property def failure(self) -> str | None: ... + @property + def sharing(self) -> tuple[int, int]: ... def start_model_analysis_session( catalog: object, request: tuple[object, ...], / ) -> NativeModelAnalysisSession | None: ... -def prove_dynamic_column_contract( +def prove_dynamic_column_contracts( request: tuple[ str, list[tuple[str, list[tuple[str, str]]]], list[tuple[str, list[tuple[str, str]]]], list[tuple[str, list[tuple[str, str]]]], list[tuple[str, list[tuple[str, str, str, str, str, str | None]]]], - str, - list[tuple[str, str, str, str, str, str | None]], + list[tuple[str, list[tuple[str, str, str, str, str, str | None]]]], ], /, -) -> tuple[ - str, - tuple[ - bool, - list[tuple[str, str | None, str]], - list[tuple[str, str | None]], - list[str], - str | None, - bool, - ] - | None, -]: ... +) -> list[_PivotContractRow] | None: ... def infer_expression_source_shapes( catalog: object, request: tuple[str, bool, list[tuple[str, str]], list[str]], / ) -> tuple[list[tuple[bool, list[tuple[str, str]] | None]], str | None]: ... +def _oracle_cte_fact_recovery( + request: tuple[ + str, + str, + list[tuple[str, list[tuple[str, str]]]], + list[tuple[str, str]], + list[tuple[str, str]] | None, + bool, + bool, + ], + /, +) -> tuple[str | None, list[tuple[str, str]], list[tuple[str, str]], list[str], list[str]]: ... # Native analysis: semantic completion. class SemanticTypeRecovery: @@ -477,13 +498,14 @@ def plan_semantic_type_recovery( str, list[str] | None, list[str], - list[tuple[str, list[tuple[str, str]]]], + list[tuple[str, list[tuple[str, str]]]] | None, list[tuple[int, str, str, bool]], list[tuple[int, str, str, int | None, int | None]], ] ], list[tuple[int, str, bool, str | None]], ], + session: NativeModelAnalysisSession | None = None, /, ) -> SemanticTypeRecovery: ... def check_semantic_metadata_rows( @@ -540,14 +562,15 @@ def complete_semantic_checks( str, str, str, - list[str], - list[tuple[str, list[tuple[str, str]]]], + list[str] | None, + list[tuple[str, list[tuple[str, str]]]] | None, list[str], str | None, ] ], list[tuple[str, list[tuple[str, str]]]], ], + session: NativeModelAnalysisSession | None = None, /, ) -> tuple[ str | None, @@ -620,8 +643,14 @@ def plan_compiled_sql_tests( request: NativeSqlTestPlanningRequest, / ) -> tuple[list[NativeSqlTestPlanRow], int, int]: ... def resolve_compiled_sql_test_chains(request: NativeSqlTestChainRequest, /) -> list[list[str]]: ... +def assemble_compiled_sql_tests( + request: NativeSqlTestAssemblyRequest, / +) -> list[NativeSqlTestAssemblyRow]: ... # Native analysis: compiled project assembly. +def check_native_sql_syntax( + request: tuple[str, list[tuple[str, list[tuple[str, str]]]]], / +) -> tuple[bool | None, str | None]: ... def assemble_project_resource_facts( request: tuple[ str, diff --git a/src/sqlbuild/adapter/type_system/_helpers/type_normalization.py b/src/sqlbuild/adapter/type_system/_helpers/type_normalization.py index b169051872..98c8f6844c 100644 --- a/src/sqlbuild/adapter/type_system/_helpers/type_normalization.py +++ b/src/sqlbuild/adapter/type_system/_helpers/type_normalization.py @@ -43,7 +43,9 @@ UNBOUNDED_TEXT_TYPE_NAMES, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.sql_analysis.main.import_polyglot import import_polyglot from sqlbuild.diagnostics.main.log_debug_event import log_debug_event @@ -59,7 +61,9 @@ def normalize_type(*, type_sql: str, dialect: TypeDialect | str | None) -> Norma type_sql=type_sql, dialect=dialect ) if native_normalized is not None: + report_native_answer(stage=NativeStage.TYPE_SYSTEM, kind="type_normalizations") return native_normalized + report_native_fallback(site=NativeFallbackSite.TYPE_NORMALIZATION) polyglot_normalized: NormalizedType | None = _normalize_with_polyglot( type_sql=type_sql, dialect=dialect, diff --git a/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py b/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py index 1f21ac3d72..c30b70555b 100644 --- a/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py +++ b/src/sqlbuild/cli/commands/_helpers/compile/pipeline.py @@ -170,6 +170,7 @@ def _analyze_compile_project( status=status, message=f"Analyzed column lineage. ({lineage_ms / 1000:.2f}s)" ) contracts_start: float = time.monotonic() + contracts_cpu_start: float = time.thread_time() contract_result: ContractValidationResult if profile_flags.skip_contracts: contract_result = ContractValidationResult(diagnostics=()) @@ -180,6 +181,7 @@ def _analyze_compile_project( dialect=adapter.sql_analysis_dialect(), ) contract_ms: int = elapsed_ms(contracts_start) + contract_cpu_ms: int = int((time.thread_time() - contracts_cpu_start) * 1000) if not profile_flags.skip_contracts: _ = complete_compile_phase( status=status, message=f"Validated model contracts. ({contract_ms / 1000:.2f}s)" @@ -255,8 +257,10 @@ def _analyze_compile_project( graph_ms=graph_ms, lineage_ms=lineage_ms, contract_ms=contract_ms, + contract_cpu_ms=contract_cpu_ms, built_in_rules_ms=rules_result.built_in_ms, custom_rules_ms=rules_result.custom_ms, + custom_rules_cpu_ms=rules_result.custom_cpu_ms, early_lint_wait_ms=early_lint_wait_ms, rule_cache_hits=rules_result.cache_hits, rule_cache_misses=rules_result.cache_misses, diff --git a/src/sqlbuild/cli/commands/_helpers/compile/sql_test_artifact_cache.py b/src/sqlbuild/cli/commands/_helpers/compile/sql_test_artifact_cache.py index c34c588311..64c5ccd69f 100644 --- a/src/sqlbuild/cli/commands/_helpers/compile/sql_test_artifact_cache.py +++ b/src/sqlbuild/cli/commands/_helpers/compile/sql_test_artifact_cache.py @@ -6,6 +6,7 @@ import json import os import platform +from dataclasses import replace from importlib.metadata import PackageNotFoundError, version from pathlib import Path from typing import cast @@ -26,7 +27,7 @@ CompileSqlTestCte, ) -_CACHE_VERSION: int = 3 +_CACHE_VERSION: int = 4 _ALGORITHM_FINGERPRINT: str = "sql-test-artifact-v4-orjson-identity" _CACHE_FILE_NAME: str = "sql-test-artifacts.json" _MAX_CACHE_BYTES: int = 10_000_000 @@ -142,6 +143,7 @@ def write_sql_test_artifact_cache( "relative_path": record.relative_path.as_posix(), "size": record.size, "mtime_ns": record.mtime_ns, + "content_sha256": record.content_sha256, } for key, record in records.items() }, @@ -161,23 +163,23 @@ def write_sql_test_artifact_cache( def artifact_matches_cache_record( *, tests_root: Path, record: SqlTestArtifactCacheRecord, identity: str -) -> Path | None: - """Return the safe existing artifact path when identity and stat metadata match.""" +) -> SqlTestArtifactCacheRecord | None: + """Return the reusable artifact's record, verifying content when only its mtime moved.""" if record.identity != identity or not _is_safe_relative_sql_path(record.relative_path): return None artifact_path: Path = tests_root / record.relative_path try: stat: os.stat_result = artifact_path.stat() + if not artifact_path.is_file() or stat.st_size != record.size: + return None + if stat.st_mtime_ns == record.mtime_ns: + return record + if _file_sha256(artifact_path) != record.content_sha256: + return None except OSError: return None - if ( - not artifact_path.is_file() - or stat.st_size != record.size - or stat.st_mtime_ns != record.mtime_ns - ): - return None - return artifact_path + return replace(record, mtime_ns=stat.st_mtime_ns) def build_sql_test_artifact_cache_record( @@ -188,6 +190,7 @@ def build_sql_test_artifact_cache_record( try: relative_path: Path = artifact_path.relative_to(tests_root) stat: os.stat_result = artifact_path.stat() + content_sha256: str = _file_sha256(artifact_path) except (OSError, ValueError): return None if not _is_safe_relative_sql_path(relative_path): @@ -197,6 +200,7 @@ def build_sql_test_artifact_cache_record( relative_path=relative_path, size=stat.st_size, mtime_ns=stat.st_mtime_ns, + content_sha256=content_sha256, ) @@ -252,6 +256,7 @@ def _record_from_payload(payload: object) -> SqlTestArtifactCacheRecord | None: relative_path: object = values.get("relative_path") size: object = values.get("size") mtime_ns: object = values.get("mtime_ns") + content_sha256: object = values.get("content_sha256") if ( not isinstance(identity, str) or not isinstance(relative_path, str) @@ -261,6 +266,7 @@ def _record_from_payload(payload: object) -> SqlTestArtifactCacheRecord | None: or not isinstance(mtime_ns, int) or isinstance(mtime_ns, bool) or mtime_ns < 0 + or not isinstance(content_sha256, str) ): return None path: Path = Path(relative_path) @@ -271,6 +277,7 @@ def _record_from_payload(payload: object) -> SqlTestArtifactCacheRecord | None: relative_path=path, size=size, mtime_ns=mtime_ns, + content_sha256=content_sha256, ) @@ -282,6 +289,10 @@ def _is_safe_relative_sql_path(path: Path) -> bool: ) +def _file_sha256(path: Path) -> str: + return hashlib.sha256(path.read_bytes()).hexdigest() + + def _payload_digest(payload: object) -> str: return hashlib.sha256(orjson.dumps(payload, option=orjson.OPT_SORT_KEYS)).hexdigest() diff --git a/src/sqlbuild/cli/commands/_helpers/compile/target_writer.py b/src/sqlbuild/cli/commands/_helpers/compile/target_writer.py index 6f04c17d01..c3aba5c289 100644 --- a/src/sqlbuild/cli/commands/_helpers/compile/target_writer.py +++ b/src/sqlbuild/cli/commands/_helpers/compile/target_writer.py @@ -48,6 +48,7 @@ FunctionLanguage, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer from sqlbuild.compiler.frontier.types import NativeStage from sqlbuild.compiler.planner.exceptions import PlannerInputError from sqlbuild.compiler.planner.main.execution.sql_test_artifacts import ( @@ -544,19 +545,20 @@ def _partition_cached_static_tests( ) cached_record: SqlTestArtifactCacheRecord | None = cached_records.get(record_key) if cached_record is not None: - cached_path: Path | None = artifact_matches_cache_record( + reusable_record: SqlTestArtifactCacheRecord | None = artifact_matches_cache_record( tests_root=tests_root, record=cached_record, identity=artifact_identity, ) - if cached_path is not None: + if reusable_record is not None: + cached_path: Path = tests_root / reusable_record.relative_path COMPILE_ARTIFACT_WRITES.kept( path=cached_path, - size=cached_record.size, - mtime_ns=cached_record.mtime_ns, + size=reusable_record.size, + mtime_ns=reusable_record.mtime_ns, ) managed_paths.add(cached_path) - current_records[record_key] = cached_record + current_records[record_key] = reusable_record continue pending.append( PendingStaticSqlTest( @@ -574,9 +576,10 @@ def _plan_static_test_artifacts( with OperationLifecycle( operation_kind="project", operation_name="sql_test_planning" ) as lifecycle: + native_planning: bool = native_stage_enabled(NativeStage.SQL_TEST_GLUE) plan_artifacts: Callable[..., tuple[NativeSqlTestArtifact, ...]] = ( plan_native_sql_test_artifacts - if native_stage_enabled(NativeStage.SQL_TEST_GLUE) + if native_planning else plan_and_render_sql_test_artifacts ) native_artifacts: tuple[NativeSqlTestArtifact, ...] = plan_artifacts( @@ -585,6 +588,8 @@ def _plan_static_test_artifacts( adapter=adapter, sql_analysis_enabled=project.settings.sql_analysis, ) + if native_planning: + report_native_answer(stage=NativeStage.SQL_TEST_GLUE, kind="sql_test_plans") lifecycle.completed(metadata={"item_count": len(native_artifacts)}) return native_artifacts diff --git a/src/sqlbuild/cli/commands/main/project/_compile.py b/src/sqlbuild/cli/commands/main/project/_compile.py index 7edbb6d3e1..6552c8e429 100644 --- a/src/sqlbuild/cli/commands/main/project/_compile.py +++ b/src/sqlbuild/cli/commands/main/project/_compile.py @@ -166,8 +166,10 @@ def _run_compile_with_status( "graph_ms": analysis.graph_ms, "lineage_ms": analysis.lineage_ms, "contracts_ms": analysis.contract_ms, + "contracts_cpu_ms": analysis.contract_cpu_ms, "built_in_rules_ms": analysis.built_in_rules_ms, "custom_rules_ms": analysis.custom_rules_ms, + "custom_rules_cpu_ms": analysis.custom_rules_cpu_ms, "early_lint_wait_ms": analysis.early_lint_wait_ms, "rule_cache_hits": analysis.rule_cache_hits, "rule_cache_misses": analysis.rule_cache_misses, diff --git a/src/sqlbuild/cli/compile/models.py b/src/sqlbuild/cli/compile/models.py index a590ab705e..dc8357891e 100644 --- a/src/sqlbuild/cli/compile/models.py +++ b/src/sqlbuild/cli/compile/models.py @@ -42,8 +42,10 @@ class CompileAnalysis: graph_ms: int lineage_ms: int contract_ms: int + contract_cpu_ms: int built_in_rules_ms: int = 0 custom_rules_ms: int = 0 + custom_rules_cpu_ms: int = 0 early_lint_wait_ms: int = 0 rule_cache_hits: int = 0 rule_cache_misses: int = 0 @@ -66,6 +68,7 @@ class SqlTestArtifactCacheRecord: relative_path: Path size: int mtime_ns: int + content_sha256: str @dataclass(frozen=True) diff --git a/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contract.py b/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contract.py deleted file mode 100644 index 803935326f..0000000000 --- a/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contract.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Prove one model's dynamic column contract natively, outside the analysis session.""" - -from __future__ import annotations - -import sqlbuild._native as _native -from sqlbuild.compiler.analysis_session._helpers.deferral_records import record_analysis_deferral -from sqlbuild.compiler.analysis_session._helpers.session_rows import ( - contract_proof, - family_rows, - shape_rows, -) -from sqlbuild.compiler.analysis_session.constants import CONTRACT_DEFERRED, DEFERRAL_DYNAMIC_PIVOT -from sqlbuild.compiler.analysis_session.types import ContractRow, ShapeRows -from sqlbuild.compiler.compile.classes.python_model_analysis import PythonModelAnalysis -from sqlbuild.compiler.compile.models import DynamicColumnContractProof -from sqlbuild.compiler.lineage.types import InferredNullability -from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily - - -def native_dynamic_contract( - *, - query_sql: str, - dialect: str | None, - families: tuple[SchemaDynamicColumnFamily, ...], - column_types_by_table: dict[str, dict[str, str]], - authoritative_column_types_by_table: dict[str, dict[str, str]], - column_nullability_by_table: dict[str, dict[str, InferredNullability]], - dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], -) -> DynamicColumnContractProof | None: - """Python's proof for declared families, or None (recorded) where Python must prove it.""" - - shapes: tuple[ShapeRows | None, ...] = ( - shape_rows(column_types_by_table), - shape_rows(authoritative_column_types_by_table), - shape_rows(column_nullability_by_table), - ) - row: ContractRow = (CONTRACT_DEFERRED, None) - if all(rows is not None for rows in shapes): - row = _native.prove_dynamic_column_contract( - ( - dialect or "generic", - shapes[0] or [], - shapes[1] or [], - shapes[2] or [], - family_rows(dynamic_families_by_table), - query_sql, - [PythonModelAnalysis.family_row(family) for family in families], - ) - ) - if row[0] == CONTRACT_DEFERRED: - record_analysis_deferral(kind=DEFERRAL_DYNAMIC_PIVOT) - return contract_proof(row[1]) diff --git a/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contracts.py b/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contracts.py new file mode 100644 index 0000000000..560870c25c --- /dev/null +++ b/src/sqlbuild/compiler/analysis_session/_helpers/dynamic_contracts.py @@ -0,0 +1,73 @@ +"""Prove dynamic column contracts natively for models outside the analysis session.""" + +from __future__ import annotations + +from typing import Any + +import sqlbuild._native as _native +from sqlbuild.compiler.analysis_session._helpers.deferral_records import record_analysis_deferral +from sqlbuild.compiler.analysis_session._helpers.session_rows import ( + contract_proof, + family_rows, + shape_rows, +) +from sqlbuild.compiler.analysis_session.constants import CONTRACT_DEFERRED, DEFERRAL_DYNAMIC_PIVOT +from sqlbuild.compiler.analysis_session.models import NativePivotTables +from sqlbuild.compiler.analysis_session.types import ContractRow, ShapeRows +from sqlbuild.compiler.compile.classes.python_model_analysis import PythonModelAnalysis +from sqlbuild.compiler.compile.models import DynamicColumnContractProof +from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily + +type _ModelRow = tuple[str, list[tuple[str, str, str, str, str, str | None]]] + + +def native_dynamic_contracts( + *, + session: Any | None, + tables: NativePivotTables, + models: tuple[tuple[str, tuple[SchemaDynamicColumnFamily, ...]], ...], +) -> tuple[DynamicColumnContractProof | None, ...]: + """Each model's proof in order, None (recorded) where Python must prove it.""" + + if not models: + return () + rows: list[_ModelRow] = [_model_row(sql=sql, families=families) for sql, families in models] + contracts: list[ContractRow] | None = ( + session.prove_dynamic_contracts(rows) + if session is not None + else _standalone_contracts(tables=tables, rows=rows) + ) + if contracts is None: + record_analysis_deferral(kind=DEFERRAL_DYNAMIC_PIVOT, count=len(models)) + return (None,) * len(models) + record_analysis_deferral( + kind=DEFERRAL_DYNAMIC_PIVOT, + count=sum(kind == CONTRACT_DEFERRED for kind, _ in contracts), + ) + return tuple(contract_proof(proof) for _, proof in contracts) + + +def _model_row(*, sql: str, families: tuple[SchemaDynamicColumnFamily, ...]) -> _ModelRow: + return (sql, list(map(PythonModelAnalysis.family_row, families))) + + +def _standalone_contracts( + *, tables: NativePivotTables, rows: list[_ModelRow] +) -> list[ContractRow] | None: + shapes: tuple[ShapeRows | None, ...] = ( + shape_rows(tables.column_types_by_table), + shape_rows(tables.authoritative_column_types_by_table), + shape_rows(tables.column_nullability_by_table), + ) + if any(shape is None for shape in shapes): + return None + return _native.prove_dynamic_column_contracts( + ( + tables.dialect or "generic", + shapes[0] or [], + shapes[1] or [], + shapes[2] or [], + family_rows(tables.dynamic_families_by_table), + rows, + ) + ) diff --git a/src/sqlbuild/compiler/analysis_session/_helpers/model_analysis.py b/src/sqlbuild/compiler/analysis_session/_helpers/model_analysis.py index c0ec38e947..a03302a8a2 100644 --- a/src/sqlbuild/compiler/analysis_session/_helpers/model_analysis.py +++ b/src/sqlbuild/compiler/analysis_session/_helpers/model_analysis.py @@ -13,15 +13,16 @@ DEFERRAL_NO_COMPACT_ANALYSIS, DEFERRAL_SESSION, ) -from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest +from sqlbuild.compiler.analysis_session.models import ( + NativeModelAnalyses, + NativeModelAnalysisRequest, +) from sqlbuild.compiler.compile.classes.python_model_analysis import PythonModelAnalysis from sqlbuild.compiler.compile.models import ModelSqlAnalysis -def native_model_analyses( - *, request: NativeModelAnalysisRequest -) -> dict[str, ModelSqlAnalysis] | None: - """Each model's analysis by name, or None (recorded) where Python must analyse.""" +def native_model_analyses(*, request: NativeModelAnalysisRequest) -> NativeModelAnalyses | None: + """Each model's analysis by name and the finished session, or None (recorded) for Python.""" catalog: Any = request.inference_profile.binding_catalog if not request.allow_compact_analysis: @@ -31,7 +32,7 @@ def native_model_analyses( record_analysis_deferral(kind=DEFERRAL_NO_CATALOG) return None if not request.model_inputs: - return {} + return NativeModelAnalyses(analyses={}, session=None) python: PythonModelAnalysis = PythonModelAnalysis( model_inputs=request.model_inputs, inference_profile=request.inference_profile, @@ -46,4 +47,7 @@ def native_model_analyses( if session is None: record_analysis_deferral(kind=DEFERRAL_SESSION) return None - return NativeModelAnalysis(request=request, python=python, catalog=catalog).analyses(session) + analyses: dict[str, ModelSqlAnalysis] | None = NativeModelAnalysis( + request=request, python=python, catalog=catalog + ).analyses(session) + return None if analyses is None else NativeModelAnalyses(analyses=analyses, session=session) diff --git a/src/sqlbuild/compiler/analysis_session/_helpers/session_rows.py b/src/sqlbuild/compiler/analysis_session/_helpers/session_rows.py index 093c361e6e..99cd11b33f 100644 --- a/src/sqlbuild/compiler/analysis_session/_helpers/session_rows.py +++ b/src/sqlbuild/compiler/analysis_session/_helpers/session_rows.py @@ -5,6 +5,15 @@ from collections.abc import Mapping from sqlbuild.adapter.contract.models import ExpressionInferenceProfile +from sqlbuild.adapter.contract.types import FunctionNullabilityRule +from sqlbuild.adapter.type_system.main.conditional_result_nullability import ( + conditional_result_nullability, +) +from sqlbuild.adapter.type_system.main.first_arg_nullability import first_arg_nullability +from sqlbuild.compiler.analysis_session.constants import ( + NULLABILITY_RULE_CONDITIONAL_RESULT, + NULLABILITY_RULE_FIRST_ARG, +) from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest from sqlbuild.compiler.analysis_session.types import ( ColumnRow, @@ -30,6 +39,11 @@ from sqlbuild.compiler.sql_analysis.models import SqlBindingDiagnostic from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily +_NULLABILITY_RULE_IDS: dict[FunctionNullabilityRule, str] = { + first_arg_nullability: NULLABILITY_RULE_FIRST_ARG, + conditional_result_nullability: NULLABILITY_RULE_CONDITIONAL_RESULT, +} + def shape_rows(shapes: Mapping[str, Mapping[str, object]]) -> ShapeRows | None: """`{relation: {column: value}}` as ordered rows, or None when a value is not text.""" @@ -66,6 +80,7 @@ def session_request( profile.sql_analysis_dialect or "generic", case_sensitive_shapes(profile=profile, dialect=profile.sql_analysis_dialect), list(profile.function_return_types.items()), + nullability_rule_rows(profile), request.rich_type_inference, *shapes, family_rows(request.dynamic_families_by_table), @@ -73,6 +88,18 @@ def session_request( ) +def nullability_rule_rows(profile: ExpressionInferenceProfile) -> list[tuple[str, str]] | None: + """Adapter nullability rules as `(name, rule id)`, or None for a rule SQLBuild lacks.""" + + rows: list[tuple[str, str]] = [] + for name, rule in profile.function_nullability_rules.items(): + rule_id: str | None = _NULLABILITY_RULE_IDS.get(rule) + if rule_id is None: + return None + rows.append((name, rule_id)) + return rows + + def contract_proof(row: ProofRow | None) -> DynamicColumnContractProof | None: """A native dynamic pivot proof as Python's, None when absent or left to Python.""" diff --git a/src/sqlbuild/compiler/analysis_session/classes/native_model_analysis.py b/src/sqlbuild/compiler/analysis_session/classes/native_model_analysis.py index 8fa6049f45..86dd27bf9e 100644 --- a/src/sqlbuild/compiler/analysis_session/classes/native_model_analysis.py +++ b/src/sqlbuild/compiler/analysis_session/classes/native_model_analysis.py @@ -14,7 +14,6 @@ compact_lineage, contract_proof, deferred_row, - inferred_columns, lineage_facts, ) from sqlbuild.compiler.analysis_session.constants import ( @@ -31,6 +30,7 @@ ) from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest from sqlbuild.compiler.analysis_session.types import ( + ColumnRow, DeferralRow, DeferredRow, FinishRow, @@ -42,6 +42,7 @@ from sqlbuild.compiler.compile.classes.python_model_analysis import PythonModelAnalysis from sqlbuild.compiler.compile.models import ( CompiledLineageColumnFact, + InferredColumn, ModelSqlAnalysis, ModelSqlAnalysisRequest, PolyglotAnalysisResult, @@ -69,6 +70,7 @@ def __init__( request.column_nullability_by_table ) self._kept: dict[tuple[int, str], PolyglotAnalysisResult] = {} + self._columns: dict[ColumnRow, InferredColumn] = {} self._deferrals: Counter[str] = Counter() def analyses( @@ -176,6 +178,23 @@ def _record_catalog_changes( }, ) + def _inferred_columns(self, rows: list[ColumnRow] | None) -> tuple[InferredColumn, ...] | None: + """Columns as Python's analysis shares them: one object per distinct column value.""" + + if rows is None: + return None + return tuple(map(self._inferred_column, rows)) + + def _inferred_column(self, row: ColumnRow) -> InferredColumn: + column: InferredColumn | None = self._columns.get(row) + if column is None: + name, data_type, nullability = row + column = InferredColumn( + name=name, type=data_type, nullability=InferredNullability(nullability) + ) + self._columns[row] = column + return column + def _model_analysis( self, *, @@ -205,7 +224,7 @@ def _model_analysis( return ModelSqlAnalysis( polyglot_analysis=PolyglotAnalysisResult( analysis_succeeded=succeeded, - columns=inferred_columns(columns), + columns=self._inferred_columns(columns), lineage_columns=lineage, has_star=has_star, star_resolved=star_resolved, diff --git a/src/sqlbuild/compiler/analysis_session/constants.py b/src/sqlbuild/compiler/analysis_session/constants.py index 9d819d795d..4a4e269c40 100644 --- a/src/sqlbuild/compiler/analysis_session/constants.py +++ b/src/sqlbuild/compiler/analysis_session/constants.py @@ -16,3 +16,5 @@ NATIVE_ANALYSIS_FAILURE_MESSAGE: str = "native compact query analysis failed" NATIVE_SESSION_FAILURE_MESSAGE: str = "native model analysis failed; falling back" NATIVE_SHAPES_FAILURE_MESSAGE: str = "native expression-source shape inference failed; falling back" +NULLABILITY_RULE_FIRST_ARG: str = "first_arg" +NULLABILITY_RULE_CONDITIONAL_RESULT: str = "conditional_result" diff --git a/src/sqlbuild/compiler/analysis_session/main/_analyze_native_model_sql.py b/src/sqlbuild/compiler/analysis_session/main/_analyze_native_model_sql.py index f7807824f2..8f72279583 100644 --- a/src/sqlbuild/compiler/analysis_session/main/_analyze_native_model_sql.py +++ b/src/sqlbuild/compiler/analysis_session/main/_analyze_native_model_sql.py @@ -3,13 +3,13 @@ from __future__ import annotations from sqlbuild.compiler.analysis_session._helpers.model_analysis import native_model_analyses -from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest -from sqlbuild.compiler.compile.models import ModelSqlAnalysis +from sqlbuild.compiler.analysis_session.models import ( + NativeModelAnalyses, + NativeModelAnalysisRequest, +) -def analyze_native_model_sql( - *, request: NativeModelAnalysisRequest -) -> dict[str, ModelSqlAnalysis] | None: - """Return each model's analysis (and any pivot proof) by name, or None to defer to Python.""" +def analyze_native_model_sql(*, request: NativeModelAnalysisRequest) -> NativeModelAnalyses | None: + """Return each model's analysis (and pivot proof) and the session, or None to defer.""" return native_model_analyses(request=request) diff --git a/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contract.py b/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contract.py deleted file mode 100644 index 9d47358f42..0000000000 --- a/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contract.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Prove a dynamic column contract natively for the preview compiler engine.""" - -from __future__ import annotations - -from sqlbuild.compiler.analysis_session._helpers.dynamic_contract import native_dynamic_contract -from sqlbuild.compiler.compile.models import DynamicColumnContractProof -from sqlbuild.compiler.lineage.types import InferredNullability -from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily - - -def prove_native_dynamic_contract( - *, - query_sql: str, - dialect: str | None, - families: tuple[SchemaDynamicColumnFamily, ...], - column_types_by_table: dict[str, dict[str, str]], - authoritative_column_types_by_table: dict[str, dict[str, str]], - column_nullability_by_table: dict[str, dict[str, InferredNullability]], - dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], -) -> DynamicColumnContractProof | None: - """Return Python's proof for declared families, or None to prove it in Python.""" - - return native_dynamic_contract( - query_sql=query_sql, - dialect=dialect, - families=families, - column_types_by_table=column_types_by_table, - authoritative_column_types_by_table=authoritative_column_types_by_table, - column_nullability_by_table=column_nullability_by_table, - dynamic_families_by_table=dynamic_families_by_table, - ) diff --git a/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contracts.py b/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contracts.py new file mode 100644 index 0000000000..4f01fb1e9f --- /dev/null +++ b/src/sqlbuild/compiler/analysis_session/main/_prove_native_dynamic_contracts.py @@ -0,0 +1,21 @@ +"""Prove dynamic column contracts natively for the preview compiler engine.""" + +from __future__ import annotations + +from typing import Any + +from sqlbuild.compiler.analysis_session._helpers.dynamic_contracts import native_dynamic_contracts +from sqlbuild.compiler.analysis_session.models import NativePivotTables +from sqlbuild.compiler.compile.models import DynamicColumnContractProof +from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily + + +def prove_native_dynamic_contracts( + *, + session: Any | None, + tables: NativePivotTables, + models: tuple[tuple[str, tuple[SchemaDynamicColumnFamily, ...]], ...], +) -> tuple[DynamicColumnContractProof | None, ...]: + """Python's proof per `(sql, families)` model from the session or `tables`; None for Python.""" + + return native_dynamic_contracts(session=session, tables=tables, models=models) diff --git a/src/sqlbuild/compiler/analysis_session/models.py b/src/sqlbuild/compiler/analysis_session/models.py index 5323f6d344..2db27e023e 100644 --- a/src/sqlbuild/compiler/analysis_session/models.py +++ b/src/sqlbuild/compiler/analysis_session/models.py @@ -3,9 +3,14 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any from sqlbuild.adapter.contract.models import ExpressionInferenceProfile -from sqlbuild.compiler.compile.models import AnalysisCacheContext, CompileModelInput +from sqlbuild.compiler.compile.models import ( + AnalysisCacheContext, + CompileModelInput, + ModelSqlAnalysis, +) from sqlbuild.compiler.lineage.types import InferredNullability from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily @@ -25,3 +30,22 @@ class NativeModelAnalysisRequest: analysis_cache: AnalysisCacheContext | None complete_binding_schemas: dict[str, dict[str, str]] dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]] + + +@dataclass(frozen=True, slots=True) +class NativeModelAnalyses: + """Each model's native analysis by name, and the finished session that produced them.""" + + analyses: dict[str, ModelSqlAnalysis] + session: Any | None + + +@dataclass(frozen=True, slots=True) +class NativePivotTables: + """The relation facts Python's dynamic pivot proofs read, for proofs outside a session.""" + + dialect: str | None + column_types_by_table: dict[str, dict[str, str]] + authoritative_column_types_by_table: dict[str, dict[str, str]] + column_nullability_by_table: dict[str, dict[str, InferredNullability]] + dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]] diff --git a/src/sqlbuild/compiler/compile/_helpers/analysis/pivot_requests.py b/src/sqlbuild/compiler/compile/_helpers/analysis/pivot_requests.py new file mode 100644 index 0000000000..9ed2ea2cad --- /dev/null +++ b/src/sqlbuild/compiler/compile/_helpers/analysis/pivot_requests.py @@ -0,0 +1,50 @@ +"""The SQL and declared families Python's dynamic pivot proof reads for each model.""" + +from __future__ import annotations + +from collections.abc import Mapping + +from sqlbuild.compiler.compile._helpers.analysis.columns import substitute_placeholder_defaults +from sqlbuild.compiler.compile._helpers.analysis.syntax_checks import model_placeholders +from sqlbuild.compiler.compile._helpers.render.cursor_intrinsics import ( + cursor_intrinsics_analysis_sql, +) +from sqlbuild.compiler.compile.models import CompileModelInput, ModelSqlAnalysis +from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily + + +def model_pivot_sql(*, query_sql: str, placeholders: dict[str, str] | None) -> str: + """Return the analysis SQL with placeholder defaults, as the pivot proof parses it.""" + + if not placeholders: + return query_sql + return substitute_placeholder_defaults(query_sql=query_sql, placeholders=placeholders) + + +def model_dynamic_families(model_input: CompileModelInput) -> tuple[SchemaDynamicColumnFamily, ...]: + """Return the dynamic column families the model's schema declares.""" + + if model_input.schema_entry is None: + return () + return model_input.schema_entry.dynamic_columns + + +def standalone_pivot_models( + *, model_inputs: tuple[CompileModelInput, ...], analyses: Mapping[str, ModelSqlAnalysis] +) -> dict[int, tuple[str, tuple[SchemaDynamicColumnFamily, ...]]]: + """Return `(sql, families)` by model index for each pivot model no analysis covered.""" + + models: dict[int, tuple[str, tuple[SchemaDynamicColumnFamily, ...]]] = {} + for index, model_input in enumerate(model_inputs): + families: tuple[SchemaDynamicColumnFamily, ...] = model_dynamic_families(model_input) + if not families or model_input.model_file.file_path.stem in analyses: + continue + query_sql: str = cursor_intrinsics_analysis_sql( + sql=model_input.query_sql, + cursor_type=model_input.config.values.get("cursor_type"), + ) + models[index] = ( + model_pivot_sql(query_sql=query_sql, placeholders=model_placeholders(model_input)), + families, + ) + return models diff --git a/src/sqlbuild/compiler/compile/_helpers/assembly/project.py b/src/sqlbuild/compiler/compile/_helpers/assembly/project.py index 87bf84e5ab..aa496d3302 100644 --- a/src/sqlbuild/compiler/compile/_helpers/assembly/project.py +++ b/src/sqlbuild/compiler/compile/_helpers/assembly/project.py @@ -23,7 +23,6 @@ record_analysis_cache_metrics, write_model_analyses, ) -from sqlbuild.compiler.compile._helpers.analysis.columns import substitute_placeholder_defaults from sqlbuild.compiler.compile._helpers.analysis.compact import ( NativeCompactAnalysis, analyze_columns_and_lineage_with_polyglot, @@ -34,6 +33,10 @@ from sqlbuild.compiler.compile._helpers.analysis.dynamic_pivot import ( analyze_dynamic_column_contract, ) +from sqlbuild.compiler.compile._helpers.analysis.pivot_requests import ( + model_dynamic_families, + model_pivot_sql, +) from sqlbuild.compiler.compile._helpers.analysis.syntax_checks import ( model_placeholders as _model_placeholders, ) @@ -86,7 +89,7 @@ analyze_model_sql_by_engine, dynamic_column_contract_by_engine, expression_source_shapes_by_engine, - project_resources_by_engine, + project_facts_by_engine, ) from sqlbuild.compiler.compile._helpers.native_stages.sql_tests import ( assemble_sql_tests_by_engine, @@ -109,6 +112,11 @@ report_mocks_reading_referencing_helpers, ) from sqlbuild.compiler.compile._helpers.sql_tests.identity import build_sql_test_case_fingerprint +from sqlbuild.compiler.compile._helpers.sql_tests.scope_deps import ( + function_sql_test_scope_deps, + macro_sql_test_scope_deps, + udf_sql_test_scope_deps, +) from sqlbuild.compiler.compile.main._scope_index_with_compile_usages import ( scope_index_with_compile_usages, ) @@ -163,11 +171,18 @@ DiagnosticSeverity, SqlTestMode, ) +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.lineage.types import ColumnLineageMode, InferredNullability from sqlbuild.compiler.planner.types import ContractPolicy +from sqlbuild.compiler.profiling.main._record_cpu import record_compile_cpu_timing from sqlbuild.compiler.profiling.main.record import record_compile_timing -from sqlbuild.compiler.project_assembly.models import NativeProjectResources -from sqlbuild.compiler.references.types import SqlReferenceKind +from sqlbuild.compiler.project_assembly.models import ( + NativeModelFacts, + NativeProjectFacts, + NativeProjectResources, +) from sqlbuild.compiler.resource_names.main.function_node_type import function_node_type from sqlbuild.compiler.scopes.models import ScopeIndex from sqlbuild.compiler.sql_analysis.constants import ( @@ -325,8 +340,12 @@ def assemble_compiled_project( else None ) model_sql_analysis_by_name: dict[str, _ModelSqlAnalysis] = {} + native_session: Any | None = None if sql_analysis_enabled: - with record_compile_timing("model_analysis_ms"): + with ( + record_compile_timing("model_analysis_ms"), + record_compile_cpu_timing("model_analysis_cpu_ms"), + ): python_analysis: partial[dict[str, _ModelSqlAnalysis]] = partial( _analyze_model_sql_in_parallel, known_functions=known_function_names(inputs.sql_function_inputs), @@ -350,20 +369,22 @@ def assemble_compiled_project( analysis_cache=analysis_cache, complete_binding_schemas=complete_binding_schemas, ) - model_sql_analysis_by_name = analyze_model_sql_by_engine( + model_sql_analysis_by_name, native_session = analyze_model_sql_by_engine( python_analysis=python_analysis, dynamic_families_by_table=dynamic_families_by_table, ) - native: NativeProjectResources | None = project_resources_by_engine( + native: NativeProjectFacts | None = project_facts_by_engine( inputs=inputs, dialect=profile.sql_analysis_dialect, analysis_model_names=analysis_model_names, - analysis_succeeded=frozenset( - name - for name, analysis in model_sql_analysis_by_name.items() - if analysis.polyglot_analysis.analysis_succeeded - ), + analyses=model_sql_analysis_by_name, + session=native_session, + column_types_by_table=column_types_by_table, + authoritative_column_types_by_table=complete_binding_schemas, + column_nullability_by_table=column_nullability_by_table, + dynamic_families_by_table=dynamic_families_by_table, ) + resources: NativeProjectResources | None = native.resources if native else None scope_index: ScopeIndex = scope_index_with_compile_usages(inputs=inputs) report_scope_index_errors(index=scope_index) effective_target_values: dict[str, object] = resolve_early_model_templates( @@ -416,7 +437,7 @@ def assemble_compiled_project( sql_validation_enabled=( analysis_model_names is None or _model_name(model_input) in analysis_model_names ), - native_deps=native.model_deps[index] if native else None, + native_model=native.models[index] if native else None, column_nullability_by_table=column_nullability_by_table, column_types_by_table=column_types_by_table, dynamic_contract_analysis_inputs=dynamic_contract_analysis_inputs, @@ -431,7 +452,7 @@ def assemble_compiled_project( source_input=source_input, target_config=inputs.effective_target, effective_vars=inputs.effective_vars, - native_entry=native.source_entries[index] if native else None, + native_entry=resources.source_entries[index] if resources else None, ) for index, source_input in enumerate(inputs.source_inputs) ), @@ -441,7 +462,7 @@ def assemble_compiled_project( defaults=inputs.project_config.defaults, target_config=inputs.effective_target, effective_vars=inputs.effective_vars, - native_destination=native.seed_destinations[index] if native else None, + native_destination=resources.seed_destinations[index] if resources else None, ) for index, seed_input in enumerate(inputs.seed_inputs) ), @@ -449,14 +470,14 @@ def assemble_compiled_project( _assemble_compiled_function( function_input=function_input, seed_names=seed_names, - native_deps=native.function_deps[index] if native else None, + native_deps=resources.function_deps[index] if resources else None, ) for index, function_input in enumerate(inputs.sql_function_inputs) ), audits=tuple( _assemble_compiled_audit( audit_input=audit_input, - native_scope_deps=native.audit_scope_deps[index] if native else None, + native_scope_deps=resources.audit_scope_deps[index] if resources else None, ) for index, audit_input in enumerate(inputs.audit_inputs) ), @@ -493,6 +514,7 @@ def assemble_compiled_project( project=project, profile=profile, resource_sql_analysis=sql_analysis_enabled and not inputs.no_sql_validation, + native_session=native_session, binding_results={ name: analysis.polyglot_analysis.binding_diagnostics for name, analysis in model_sql_analysis_by_name.items() @@ -519,7 +541,7 @@ def _assemble_compiled_model( model_input: CompileModelInput, sql_analysis_enabled: bool, sql_validation_enabled: bool = True, - native_deps: tuple[CompiledObjectKey, ...] | None = None, + native_model: NativeModelFacts | None = None, column_nullability_by_table: dict[str, dict[str, InferredNullability]] | None = None, column_types_by_table: dict[str, dict[str, str]] | None = None, dynamic_contract_analysis_inputs: _DynamicContractAnalysisInputs | None = None, @@ -528,6 +550,7 @@ def _assemble_compiled_model( allow_compact_analysis: bool = False, ) -> CompiledModel: model_name: str = model_input.model_file.file_path.stem + native_deps: tuple[CompiledObjectKey, ...] | None = native_model.deps if native_model else None syntax_validated: bool = native_deps is not None profile: ExpressionInferenceProfile = inference_profile or ExpressionInferenceProfile() analysis_query_sql: str = cursor_intrinsics_analysis_sql( @@ -595,22 +618,12 @@ def _assemble_compiled_model( ) dynamic_column_contract: DynamicColumnContractProof | None = dynamic_column_contract_by_engine( sql_analysis=sql_analysis, + native_proof=native_model.dynamic_contract if native_model else None, python_proof=partial( analyze_dynamic_column_contract, - query_sql=( - substitute_placeholder_defaults( - query_sql=analysis_query_sql, - placeholders=placeholders, - ) - if placeholders - else analysis_query_sql - ), + query_sql=model_pivot_sql(query_sql=analysis_query_sql, placeholders=placeholders), dialect=profile.sql_analysis_dialect, - families=( - model_input.schema_entry.dynamic_columns - if model_input.schema_entry is not None - else () - ), + families=model_dynamic_families(model_input), column_types_by_table=column_types_by_table or {}, authoritative_column_types_by_table=( dynamic_contract_analysis_inputs.authoritative_column_types_by_table @@ -1570,6 +1583,8 @@ def _build_source_relation_entry( def _expand_target_value(*, value: str | None, effective_vars: dict[str, object]) -> str | None: if value is None: return None + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="source_target") return str( expand_template_data( value=value, @@ -1720,17 +1735,17 @@ def _assemble_compiled_sql_test( target_model_names: tuple[str, ...] = () if isinstance(test_input.payload, CompileDirectLogicSqlTestInputPayload): if test_input.payload.mode == SqlTestMode.MACRO: - scope_deps = _macro_sql_test_scope_deps( + scope_deps = macro_sql_test_scope_deps( tested_macro_names=test_input.payload.tested_resource_names, model_inputs=model_inputs, ) elif test_input.payload.mode == SqlTestMode.UDF: - scope_deps = _udf_sql_test_scope_deps( + scope_deps = udf_sql_test_scope_deps( tested_udf_names=test_input.payload.tested_resource_names, model_inputs=model_inputs, ) else: - scope_deps = _function_sql_test_scope_deps( + scope_deps = function_sql_test_scope_deps( tested_function_names=test_input.payload.tested_resource_names, ) compiled_payload = CompiledDirectLogicSqlTestPayload( @@ -1851,59 +1866,6 @@ def _assemble_compiled_sql_test( ) -def _macro_sql_test_scope_deps( - *, tested_macro_names: tuple[str, ...], model_inputs: tuple[CompileModelInput, ...] -) -> tuple[CompiledObjectKey, ...]: - tested_names: frozenset[str] = frozenset(tested_macro_names) - scope_deps: list[CompiledObjectKey] = [] - model_input: CompileModelInput - for model_input in model_inputs: - model_macro_deps: frozenset[str] = frozenset( - model_input.macro_deps or find_macro_call_names(model_input.macro_source_sql) - ) - if not tested_names.intersection(model_macro_deps): - continue - scope_deps.append( - CompiledObjectKey( - resource_type=CompiledResourceType.MODEL, - name=model_input.model_file.file_path.stem, - ) - ) - return tuple(scope_deps) - - -def _udf_sql_test_scope_deps( - *, tested_udf_names: tuple[str, ...], model_inputs: tuple[CompileModelInput, ...] -) -> tuple[CompiledObjectKey, ...]: - tested_names: frozenset[str] = frozenset(tested_udf_names) - scope_deps: list[CompiledObjectKey] = [] - model_input: CompileModelInput - for model_input in model_inputs: - model_udf_deps: frozenset[str] = frozenset( - reference.ref_name - for reference in model_input.references - if reference.ref_kind == SqlReferenceKind.UDF - ) - if not tested_names.intersection(model_udf_deps): - continue - scope_deps.append( - CompiledObjectKey( - resource_type=CompiledResourceType.MODEL, - name=model_input.model_file.file_path.stem, - ) - ) - return tuple(scope_deps) - - -def _function_sql_test_scope_deps( - *, tested_function_names: tuple[str, ...] -) -> tuple[CompiledObjectKey, ...]: - return tuple( - CompiledObjectKey(resource_type=CompiledResourceType.TABLE_FN, name=function_name) - for function_name in tested_function_names - ) - - def _build_test_model_query_overrides( *, test_input: CompileSqlTestInput, diff --git a/src/sqlbuild/compiler/compile/_helpers/assembly/targets.py b/src/sqlbuild/compiler/compile/_helpers/assembly/targets.py index 28bd9e7bed..0f535172a1 100644 --- a/src/sqlbuild/compiler/compile/_helpers/assembly/targets.py +++ b/src/sqlbuild/compiler/compile/_helpers/assembly/targets.py @@ -8,6 +8,9 @@ from sqlbuild.compiler.compile._helpers.render.templating import expand_template_data from sqlbuild.compiler.compile.constants import PRESERVE_TARGET_VALUE from sqlbuild.compiler.compile.models import CompiledRelationLocation, CompileModelInput +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.spec.contracts.models import DefaultsConfig, SchemaSeedEntry, TargetConfig @@ -150,6 +153,8 @@ def _expand_seed_environment_value( ) -> str | None: if raw_value == PRESERVE_TARGET_VALUE: return None + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="seed_target") return str( expand_template_data( value=raw_value, @@ -174,6 +179,8 @@ def _expand_seed_target_value( ) -> str | None: if raw_value == PRESERVE_TARGET_VALUE: return None + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="seed_target") return str( expand_template_data( value=raw_value, diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/audits.py b/src/sqlbuild/compiler/compile/_helpers/attachment/audits.py index 878f094901..557365de07 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/audits.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/audits.py @@ -73,7 +73,9 @@ DiscoveredProjectInputs, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.references.types import SqlReferenceKind from sqlbuild.compiler.scopes.models import ( DeclarationIdentity, @@ -660,6 +662,10 @@ def build_attached_audit_input( if native_stage_enabled(NativeStage.ATTACHMENTS) else None ) + if native_rendering is None and native_stage_enabled(NativeStage.ATTACHMENTS): + report_native_fallback(site=NativeFallbackSite.AUDIT_RENDERING) + if native_rendering is not None: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="audit_renderings") if native_rendering is not None and native_rendering.render_error is not None: raise CompileInputError(native_rendering.render_error, bridge_independent=True) rendered_sql_body, rendered_evidence_sql = ( diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/core.py b/src/sqlbuild/compiler/compile/_helpers/attachment/core.py index 217d15ffd0..523b117c29 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/core.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/core.py @@ -143,7 +143,9 @@ SqlHookEntry, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.model_config.main._parse_native_header_metadata import ( parse_native_header_metadata, ) @@ -554,6 +556,9 @@ def _build_model_inputs( if native_stage_enabled(NativeStage.MODEL_LOOP) else () ) + report_native_answer( + stage=NativeStage.MODEL_LOOP, kind="variable_substitutions", units=len(prepared_files) + ) loop: _ModelInputLoop = _ModelInputLoop( discovered_inputs=discovered_inputs, context=context, @@ -745,7 +750,14 @@ def _build_model_input( if prepared_var_substituted_sql is not None else None ) + if declaration_expansion is not None and native_stage_enabled(NativeStage.MODEL_LOOP): + report_native_answer(stage=NativeStage.MODEL_LOOP, kind="declaration_expansions") if declaration_expansion is None: + if native_stage_enabled(NativeStage.MODEL_LOOP): + report_native_fallback( + site=NativeFallbackSite.DECLARATION_REFERENCES, + kind="scan" if prepared_var_substituted_sql is not None else "after_variables", + ) declaration_expansion = expand_declaration_references_result( sql=var_substituted_sql, file_path=model_file.file_path, @@ -764,6 +776,8 @@ def _build_model_input( consumer=model_identity, ) expanded_query_sql: str = macro_expansion.sql + if native_stage_enabled(NativeStage.MODEL_LOOP): + report_native_fallback(site=NativeFallbackSite.CURSOR_INTRINSIC_VALIDATION) expanded_query_sql = get_validated_model_cursor_intrinsics( sql=expanded_query_sql, config_values=effective_config.values, @@ -1227,6 +1241,7 @@ def _native_seed_inputs( "has no matching CSV file under seeds/", bridge_independent=True, ) + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="seed_pairs", units=len(pairs)) return tuple( CompileSeedInput( seed_file=seed_files[file_index], @@ -1263,6 +1278,8 @@ def build_effective_connection( connection.update(local_config.connections.get(connection_name, {})) connection.update(target_config.connection) connection.update(local_config.connection) + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="connection") return cast( dict[str, object], expand_template_data( @@ -1305,6 +1322,8 @@ def build_effective_vars( values.update(target_config.vars) values.update(local_config.vars) values.update(cli_vars) + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="effective_vars") return expand_effective_vars(values) diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/declaration_scope.py b/src/sqlbuild/compiler/compile/_helpers/attachment/declaration_scope.py index ec401a01c1..768429f794 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/declaration_scope.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/declaration_scope.py @@ -28,7 +28,9 @@ ) from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.scopes.classes.native_scope_index import NativeScopeIndex from sqlbuild.compiler.scopes.exceptions import ScopeValidationError from sqlbuild.compiler.scopes.main._build_scope_index import build_scope_index @@ -121,6 +123,7 @@ def _build_native_declaration_scope( discovered_inputs=discovered_inputs, loaded_macros=loaded_macros ) if native is None: + report_native_fallback(site=NativeFallbackSite.SCOPE_INDEX) return None try: validate_scope_index(index=native.index) @@ -139,11 +142,14 @@ def _build_native_declaration_scope( if fault is not None: raise CompileInputError(fault, bridge_independent=True) if not native.grant(facts): + report_native_fallback(site=NativeFallbackSite.SCOPE_GRANTS) return None index: ScopeIndex = native.index_with_relationships() lookup: ScopeLookup | None = native.lookup(index=index) if lookup is None: + report_native_fallback(site=NativeFallbackSite.SCOPE_LOOKUP) return None + report_native_answer(stage=NativeStage.DECLARATION_SCOPES, kind="scope_indexes") return DeclarationScopeBuild( loaded_macros=loaded_macros, index=index, diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/functions.py b/src/sqlbuild/compiler/compile/_helpers/attachment/functions.py index f748035c3f..f88834410f 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/functions.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/functions.py @@ -73,7 +73,9 @@ DiscoveredSqlFunctionFile, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.scopes.models import ResourceIdentity from sqlbuild.compiler.scopes.types import ResourceKind from sqlbuild.compiler.sql_analysis.main.import_polyglot import import_polyglot @@ -337,7 +339,10 @@ def _sql_function_header( if native else None ) + if native and native_header is None: + report_native_fallback(site=NativeFallbackSite.FUNCTION_HEADER, kind="sql") if native_header is not None: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="function_headers") _raise_header_failure(header=native_header, stage=HEADER_START_STAGE) arguments: tuple[FunctionArgument, ...] = _expanded_native_arguments( header=native_header, @@ -485,6 +490,10 @@ def _build_python_function_input( if native else None ) + if native and native_header is None: + report_native_fallback(site=NativeFallbackSite.FUNCTION_HEADER, kind="python") + if native_header is not None: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="function_headers") arguments: tuple[FunctionArgument, ...] returns: str runtime_version: str diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/model_config.py b/src/sqlbuild/compiler/compile/_helpers/attachment/model_config.py index eb2dba4c8b..db35c7d23e 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/model_config.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/model_config.py @@ -65,6 +65,9 @@ PythonHookEntry, SqlHookEntry, ) +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.model_config.main._native_config_contains_macro_call import ( native_config_contains_macro_call, ) @@ -136,6 +139,7 @@ def contains_config_templates( native: bool | None = native_config_contains_template(values) if native is not None: return native + report_native_fallback(site=NativeFallbackSite.CONFIG_PRESENCE_SCAN, kind="templates") return _contains_template_data_cached( value=values, cache=scan_cache.template_presence if scan_cache is not None else None ) @@ -152,6 +156,7 @@ def contains_config_macro_calls( ) if native is not None: return native + report_native_fallback(site=NativeFallbackSite.CONFIG_PRESENCE_SCAN, kind="macros") return _contains_model_config_macro_cached( values=values, cache=scan_cache.macro_presence if scan_cache is not None else None ) @@ -372,6 +377,8 @@ def build_model_header_schema_entry( ) else None ) + if native_metadata is not None and native is None: + report_native_fallback(site=NativeFallbackSite.CONFIG_HEADER_METADATA, kind="stale") if native is not None and native.columns_error is not None: raise native_config_error(error=native.columns_error, bridge_independent=True) local_columns: tuple[SchemaColumn, ...] = ( @@ -931,7 +938,9 @@ def build_native_model_config( model_file.header_values, matched_path_default, model_file.file_path.stem ) if built is None: + report_native_fallback(site=NativeFallbackSite.CONFIG_BUILD) return None + report_native_answer(stage=NativeStage.MODEL_CONFIG, kind="config_builds") if isinstance(built, _native.NativeConfigError): raise native_config_error(error=built, bridge_independent=True) values, header_keys, namespace, overrides, reads = built @@ -1018,7 +1027,9 @@ def validate_model_config( if isinstance(outcome, _native.NativeConfigError): raise native_validation_error(error=outcome, values=request.config.values) if outcome: + report_native_answer(stage=NativeStage.MODEL_CONFIG, kind="validations") return + report_native_fallback(site=NativeFallbackSite.CONFIG_VALIDATORS) run_python_model_validators(context=context, request=request) diff --git a/src/sqlbuild/compiler/compile/_helpers/attachment/scope_relationships.py b/src/sqlbuild/compiler/compile/_helpers/attachment/scope_relationships.py index a722180754..00903c0608 100644 --- a/src/sqlbuild/compiler/compile/_helpers/attachment/scope_relationships.py +++ b/src/sqlbuild/compiler/compile/_helpers/attachment/scope_relationships.py @@ -33,6 +33,8 @@ ) from sqlbuild.compiler.compile.types import SqlTestMode from sqlbuild.compiler.discovery.models import DiscoveredProjectInputs, DiscoveredSqlTestFile +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite from sqlbuild.compiler.scopes.main._native_expected_model_names import ( native_expected_model_names, ) @@ -158,6 +160,10 @@ def extract_scope_relationship_facts( if isinstance(scanned, str): faults.append(ScopeRelationshipFault(scenario.relative_path, scanned)) continue + if scanned is None: + report_native_fallback( + site=NativeFallbackSite.SCOPE_RELATIONSHIP_CTES, kind="scenario_expected_names" + ) try: facts.append( RelationshipFact( @@ -211,6 +217,10 @@ def _expected_names_by_file( if native_names is not None: file_names.append(native_names) continue + if scan_natively: + report_native_fallback( + site=NativeFallbackSite.SCOPE_RELATIONSHIP_CTES, kind="expected_names" + ) try: file_names.append( extract_sql_test_expected_model_names( @@ -317,6 +327,7 @@ def _natively_tested_macro_names( """Macros a macro test's actual CTE calls, scanned natively where Python's scanner is exact.""" if native_ctes is None: + report_native_fallback(site=NativeFallbackSite.SCOPE_RELATIONSHIP_CTES, kind="macro_test") return _tested_macro_names(sql=sql, file_label=file_label, syntax=syntax) if isinstance(native_ctes, str): raise CompileInputError(native_ctes, bridge_independent=True) diff --git a/src/sqlbuild/compiler/compile/_helpers/diagnostics/recovery.py b/src/sqlbuild/compiler/compile/_helpers/diagnostics/recovery.py index 521430a59e..6f5c027477 100644 --- a/src/sqlbuild/compiler/compile/_helpers/diagnostics/recovery.py +++ b/src/sqlbuild/compiler/compile/_helpers/diagnostics/recovery.py @@ -5,6 +5,7 @@ import re from collections import Counter from dataclasses import replace +from typing import Any from sqlbuild.adapter.contract.models import ExpressionInferenceProfile from sqlbuild.compiler.compile._helpers.assembly.metadata_validation import ( @@ -28,6 +29,7 @@ CompilerDiagnostic, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer from sqlbuild.compiler.frontier.types import NativeStage from sqlbuild.compiler.semantic_checks.main._complete_native_semantic_diagnostics import ( complete_native_semantic_diagnostics, @@ -44,6 +46,7 @@ def complete_semantic_diagnostics( profile: ExpressionInferenceProfile, binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]], resource_sql_analysis: bool = True, + native_session: Any | None = None, ) -> CompiledProject: """Recover type facts before metadata checks, then explain retained root diagnostics.""" if native_stage_enabled(NativeStage.SEMANTIC_CHECKS): @@ -52,8 +55,10 @@ def complete_semantic_diagnostics( profile=profile, binding_results=binding_results, resource_sql_analysis=resource_sql_analysis, + session=native_session, ) if native_project is not None: + report_native_answer(stage=NativeStage.SEMANTIC_CHECKS, kind="semantic_completions") return native_project project = recover_output_types(project=project, binding_results=binding_results) project = replace( diff --git a/src/sqlbuild/compiler/compile/_helpers/diagnostics/sql_analysis_opt_outs.py b/src/sqlbuild/compiler/compile/_helpers/diagnostics/sql_analysis_opt_outs.py index 020aa3568e..6db1cd78b5 100644 --- a/src/sqlbuild/compiler/compile/_helpers/diagnostics/sql_analysis_opt_outs.py +++ b/src/sqlbuild/compiler/compile/_helpers/diagnostics/sql_analysis_opt_outs.py @@ -8,6 +8,7 @@ from pathlib import Path from sqlbuild.compiler.compile._helpers.analysis.validation import ( + hook_sql_statements, validate_hook_sql_syntax, validate_sql_syntax, ) @@ -31,6 +32,11 @@ SQL_ANALYSIS_CONFIG_KEY, ) from sqlbuild.compiler.discovery.models import DiscoveredSqlModelFile +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.project_assembly.main._check_native_sql_syntax import ( + check_native_sql_syntax, +) from sqlbuild.errors.setting_help.main.join_helps import join_helps from sqlbuild.errors.setting_help.main.setting_help import setting_help from sqlbuild.errors.setting_help.main.setting_note import setting_note @@ -66,6 +72,24 @@ def rejected_sql_analysis_opt_out(request: SqlAnalysisOptOutRequest) -> SourceLo or not any(request.config.values.get(key) is False for key in _OPT_OUT_KEYS) ): return None + if not _parses(request): + return None + return _opt_out_location(request) + + +def _parses(request: SqlAnalysisOptOutRequest) -> bool: + """Whether the model query and every hook pass Python's syntax validation.""" + + if native_stage_enabled(NativeStage.PROJECT_ASSEMBLY): + statements: list[str] = [request.query_sql] + for hook_name in _HOOK_KEYS: + statements.extend(hook_sql_statements(request.config.values.get(hook_name))) + native: bool | None = check_native_sql_syntax( + checks=tuple((statement, request.placeholders) for statement in statements), + dialect=None, + ) + if native is not None: + return native model_name: str = request.model_file.file_path.stem try: validate_sql_syntax( @@ -83,8 +107,8 @@ def rejected_sql_analysis_opt_out(request: SqlAnalysisOptOutRequest) -> SourceLo placeholders=request.placeholders, ) except CompileInputError: - return None - return _opt_out_location(request) + return False + return True def reject_unneeded_sql_analysis_opt_outs(project: CompiledProject) -> CompiledProject: diff --git a/src/sqlbuild/compiler/compile/_helpers/macro_bridge/expansion.py b/src/sqlbuild/compiler/compile/_helpers/macro_bridge/expansion.py index 6c46bb639c..dd2456cccd 100644 --- a/src/sqlbuild/compiler/compile/_helpers/macro_bridge/expansion.py +++ b/src/sqlbuild/compiler/compile/_helpers/macro_bridge/expansion.py @@ -21,6 +21,9 @@ MacroExpansionState, ) from sqlbuild.compiler.frontier.exceptions import NativeStageMismatchError +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.macro_bridge.classes.macro_bridge import MacroBridge from sqlbuild.compiler.macro_bridge.constants import ( ARGUMENT_REFERENCE_EVENT, @@ -60,6 +63,7 @@ def expand_bridged_sql_macros( macro_context=state.macro_context, ) if call_class is None: + report_native_fallback(site=NativeFallbackSite.MACRO_CALL_RESOLUTION) sites = None break call_classes.append(call_class) @@ -83,6 +87,7 @@ def expand_bridged_sql_macros( ) for site, call_class in zip(sites, call_classes, strict=True) ] + report_native_answer(stage=NativeStage.MACRO_CALLS, kind="bridged_calls", units=len(sites)) return bridge.splice(sql=sql, sites=sites, outputs=outputs) diff --git a/src/sqlbuild/compiler/compile/_helpers/native_stages/assembly.py b/src/sqlbuild/compiler/compile/_helpers/native_stages/assembly.py index 2c1f1bc21d..8d44c731cb 100644 --- a/src/sqlbuild/compiler/compile/_helpers/native_stages/assembly.py +++ b/src/sqlbuild/compiler/compile/_helpers/native_stages/assembly.py @@ -3,6 +3,7 @@ from __future__ import annotations from functools import partial +from typing import Any from sqlbuild.adapter.contract.models import ExpressionInferenceProfile from sqlbuild.compiler.analysis_session.main._analyze_native_model_sql import ( @@ -11,10 +12,15 @@ from sqlbuild.compiler.analysis_session.main._infer_native_expression_source_shapes import ( infer_native_expression_source_shapes, ) -from sqlbuild.compiler.analysis_session.main._prove_native_dynamic_contract import ( - prove_native_dynamic_contract, +from sqlbuild.compiler.analysis_session.main._prove_native_dynamic_contracts import ( + prove_native_dynamic_contracts, ) -from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest +from sqlbuild.compiler.analysis_session.models import ( + NativeModelAnalyses, + NativeModelAnalysisRequest, + NativePivotTables, +) +from sqlbuild.compiler.compile._helpers.analysis.pivot_requests import standalone_pivot_models from sqlbuild.compiler.compile._helpers.analysis.syntax_checks import model_syntax_checks from sqlbuild.compiler.compile._helpers.assembly.semantic_shapes import ( get_expression_source_shapes, @@ -25,34 +31,90 @@ ModelSqlAnalysis, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage +from sqlbuild.compiler.lineage.types import InferredNullability from sqlbuild.compiler.project_assembly.main._assemble_native_project_resources import ( assemble_native_project_resources, ) -from sqlbuild.compiler.project_assembly.models import NativeProjectResources +from sqlbuild.compiler.project_assembly.models import ( + NativeModelFacts, + NativeProjectFacts, + NativeProjectResources, +) from sqlbuild.spec.contracts.models import SchemaDynamicColumnFamily -def project_resources_by_engine( +def project_facts_by_engine( *, inputs: CompileProjectInputs, dialect: str | None, analysis_model_names: frozenset[str] | None, - analysis_succeeded: frozenset[str], -) -> NativeProjectResources | None: - """Return the natively assembled resource facts, or None where Python must assemble them.""" + analyses: dict[str, ModelSqlAnalysis], + session: Any | None, + column_types_by_table: dict[str, dict[str, str]], + authoritative_column_types_by_table: dict[str, dict[str, str]], + column_nullability_by_table: dict[str, dict[str, InferredNullability]], + dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], +) -> NativeProjectFacts | None: + """Return the native project facts, or None where Python must derive all of them.""" if not native_stage_enabled(NativeStage.PROJECT_ASSEMBLY): return None - return assemble_native_project_resources( + resources: NativeProjectResources | None = assemble_native_project_resources( inputs=inputs, dialect=dialect, syntax_checks=model_syntax_checks( model_inputs=inputs.model_inputs, analysis_model_names=analysis_model_names, - analysis_succeeded=analysis_succeeded, + analysis_succeeded=frozenset( + name + for name, analysis in analyses.items() + if analysis.polyglot_analysis.analysis_succeeded + ), ), ) + if resources is not None: + report_native_answer(stage=NativeStage.PROJECT_ASSEMBLY, kind="project_assemblies") + else: + report_native_fallback(site=NativeFallbackSite.PROJECT_ASSEMBLY) + pivots: dict[int, tuple[str, tuple[SchemaDynamicColumnFamily, ...]]] = ( + standalone_pivot_models(model_inputs=inputs.model_inputs, analyses=analyses) + if native_stage_enabled(NativeStage.MODEL_ANALYSIS) + else {} + ) + proofs: dict[int, DynamicColumnContractProof | None] = dict( + zip( + pivots, + prove_native_dynamic_contracts( + session=session, + tables=NativePivotTables( + dialect=dialect, + column_types_by_table=column_types_by_table, + authoritative_column_types_by_table=authoritative_column_types_by_table, + column_nullability_by_table=column_nullability_by_table, + dynamic_families_by_table=dynamic_families_by_table, + ), + models=tuple(pivots.values()), + ), + strict=True, + ) + ) + proven: int = len([proof for proof in proofs.values() if proof is not None]) + report_native_answer( + stage=NativeStage.MODEL_ANALYSIS, kind="dynamic_contract_proofs", units=proven + ) + return NativeProjectFacts( + models=tuple( + NativeModelFacts( + deps=resources.model_deps[index] if resources is not None else None, + dynamic_contract=proofs.get(index), + ) + for index in range(len(inputs.model_inputs)) + ), + resources=resources, + ) def expression_source_shapes_by_engine( @@ -65,6 +127,9 @@ def expression_source_shapes_by_engine( infer_native_expression_source_shapes(expressions=expressions, profile=profile) ) if native_shapes is not None: + report_native_answer( + stage=NativeStage.MODEL_ANALYSIS, kind="expression_shapes", units=len(native_shapes) + ) return native_shapes return get_expression_source_shapes(expressions=expressions, profile=profile) @@ -73,37 +138,33 @@ def analyze_model_sql_by_engine( *, python_analysis: partial[dict[str, ModelSqlAnalysis]], dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], -) -> dict[str, ModelSqlAnalysis]: - """Analyze models natively with the Python analysis's arguments, or run the Python analysis.""" +) -> tuple[dict[str, ModelSqlAnalysis], Any | None]: + """Analyze models natively, or with Python; also return the finished native session.""" if native_stage_enabled(NativeStage.MODEL_ANALYSIS): - native_analyses: dict[str, ModelSqlAnalysis] | None = analyze_native_model_sql( + native: NativeModelAnalyses | None = analyze_native_model_sql( request=NativeModelAnalysisRequest( **python_analysis.keywords, dynamic_families_by_table=dynamic_families_by_table ) ) - if native_analyses is not None: - return native_analyses - return python_analysis() + if native is not None: + report_native_answer( + stage=NativeStage.MODEL_ANALYSIS, kind="model_analyses", units=len(native.analyses) + ) + return native.analyses, native.session + return python_analysis(), None def dynamic_column_contract_by_engine( *, sql_analysis: ModelSqlAnalysis | None, + native_proof: DynamicColumnContractProof | None, python_proof: partial[DynamicColumnContractProof | None], ) -> DynamicColumnContractProof | None: - """Return the proof native analysis carries or proves alone, or prove it in Python.""" + """Return the proof native analysis carries or proved alone, or prove it in Python.""" if sql_analysis is not None and sql_analysis.dynamic_column_contract is not None: return sql_analysis.dynamic_column_contract - if ( - sql_analysis is None - and python_proof.keywords["families"] - and native_stage_enabled(NativeStage.MODEL_ANALYSIS) - ): - native: DynamicColumnContractProof | None = prove_native_dynamic_contract( - **python_proof.keywords - ) - if native is not None: - return native + if native_proof is not None: + return native_proof return python_proof() diff --git a/src/sqlbuild/compiler/compile/_helpers/native_stages/sql_tests.py b/src/sqlbuild/compiler/compile/_helpers/native_stages/sql_tests.py index fde4b1cf87..06f93455d9 100644 --- a/src/sqlbuild/compiler/compile/_helpers/native_stages/sql_tests.py +++ b/src/sqlbuild/compiler/compile/_helpers/native_stages/sql_tests.py @@ -4,16 +4,20 @@ from collections.abc import Callable +from sqlbuild.compiler.compile._helpers.diagnostics.collector import report_compile_diagnostic from sqlbuild.compiler.compile.models import ( CompiledSqlTest, CompileProjectInputs, CompileSqlTestInput, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.sql_test_glue.main._assemble_native_sql_tests import ( assemble_native_sql_tests, ) +from sqlbuild.compiler.sql_test_glue.models import NativeSqlTestAssembly def assemble_sql_tests_by_engine( @@ -23,8 +27,17 @@ def assemble_sql_tests_by_engine( ) -> tuple[CompiledSqlTest, ...]: """Assemble every SQL test natively, or each test in Python where native defers.""" - if native_stage_enabled(NativeStage.SQL_TEST_GLUE): - native_tests: tuple[CompiledSqlTest, ...] | None = assemble_native_sql_tests(inputs=inputs) - if native_tests is not None: - return native_tests - return tuple(assemble_python_test(test_input) for test_input in inputs.test_inputs) + if not native_stage_enabled(NativeStage.SQL_TEST_GLUE): + return tuple(assemble_python_test(test_input) for test_input in inputs.test_inputs) + native: tuple[NativeSqlTestAssembly | None, ...] = assemble_native_sql_tests(inputs=inputs) + tests: list[CompiledSqlTest] = [] + for test_input, assembly in zip(inputs.test_inputs, native, strict=True): + if assembly is None: + report_native_fallback(site=NativeFallbackSite.SQL_TEST_ASSEMBLY) + tests.append(assemble_python_test(test_input)) + continue + for key, diagnostic in assembly.diagnostics: + report_compile_diagnostic(key=key, diagnostic=diagnostic) + report_native_answer(stage=NativeStage.SQL_TEST_GLUE, kind="sql_test_assemblies") + tests.append(assembly.test) + return tuple(tests) diff --git a/src/sqlbuild/compiler/compile/_helpers/refs/references.py b/src/sqlbuild/compiler/compile/_helpers/refs/references.py index 5fd0299871..1d362798ee 100644 --- a/src/sqlbuild/compiler/compile/_helpers/refs/references.py +++ b/src/sqlbuild/compiler/compile/_helpers/refs/references.py @@ -34,7 +34,9 @@ SqlReferenceScanFailure, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.references.types import SqlReferenceKind from sqlbuild.compiler.sql_analysis.main._find_matching_paren import find_matching_paren from sqlbuild.compiler.sql_analysis.main._skip_dialect_non_code import dialect_non_code_end @@ -99,7 +101,11 @@ def _reference_scan_outcome( native: SqlReferenceScan | SqlReferenceScanFailure | None = extract_native_sql_references( sql=sql, syntax=syntax ) - return native if native is not None else python_reference_scan(sql=sql, syntax=syntax) + if native is not None: + report_native_answer(stage=NativeStage.REFERENCE_EXTRACTION, kind="reference_scans") + return native + report_native_fallback(site=NativeFallbackSite.REFERENCE_SCAN) + return python_reference_scan(sql=sql, syntax=syntax) if syntax.reads_differently_from_generic(sql): return python_reference_scan(sql=sql, syntax=syntax) native_references: list[tuple[str, str, str | None, int | None]] | None = ( diff --git a/src/sqlbuild/compiler/compile/_helpers/render/context_templates.py b/src/sqlbuild/compiler/compile/_helpers/render/context_templates.py index 1a544e1ad8..b995a5e940 100644 --- a/src/sqlbuild/compiler/compile/_helpers/render/context_templates.py +++ b/src/sqlbuild/compiler/compile/_helpers/render/context_templates.py @@ -15,6 +15,9 @@ PRESERVE_TARGET_VALUE, ) from sqlbuild.compiler.compile.types import CompileContextKey +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.model_config.constants import ENVIRONMENT_READ from sqlbuild.compiler.model_config.main._expand_native_config_templates import ( expand_native_config_templates, @@ -284,6 +287,13 @@ def expand_config_templates( ): record_template_reads(outcome.reads) raise native_config_error(error=outcome.error, bridge_independent=True) + if native: + report_native_fallback( + site=NativeFallbackSite.CONFIG_TEMPLATES, + kind="unsupported" if outcome is None or isinstance(outcome, str) else "missing_value", + ) + elif native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="config") return expand_template_data( value=value, variables=variables, diff --git a/src/sqlbuild/compiler/compile/_helpers/render/cursor_intrinsics.py b/src/sqlbuild/compiler/compile/_helpers/render/cursor_intrinsics.py index 6b18d042b6..22b464a250 100644 --- a/src/sqlbuild/compiler/compile/_helpers/render/cursor_intrinsics.py +++ b/src/sqlbuild/compiler/compile/_helpers/render/cursor_intrinsics.py @@ -12,7 +12,9 @@ ) from sqlbuild.compiler.compile.exceptions import CompileInputError from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.planner.constants import ( MICROBATCH_END_SENTINEL, MICROBATCH_START_SENTINEL, @@ -66,10 +68,13 @@ def reject_cursor_intrinsics(*, sql: str, context: str) -> None: free, error = _native.sql_free_of_cursor_intrinsics( sql, [MICROBATCH_START_SENTINEL, MICROBATCH_END_SENTINEL], context ) + if free or error is not None: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="cursor_intrinsic_rejections") if free: return if error is not None: raise CompileInputError(error) + report_native_fallback(site=NativeFallbackSite.CURSOR_INTRINSIC_REJECTION) _assert_no_reserved_cursor_markers(sql=sql, context=context) _, found = _transform_cursor_intrinsics( sql=sql, diff --git a/src/sqlbuild/compiler/compile/_helpers/render/declarations.py b/src/sqlbuild/compiler/compile/_helpers/render/declarations.py index 87043b82d7..644bb14747 100644 --- a/src/sqlbuild/compiler/compile/_helpers/render/declarations.py +++ b/src/sqlbuild/compiler/compile/_helpers/render/declarations.py @@ -33,7 +33,8 @@ ModelSchemaDeclaration, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.model_loop.constants import ( ENUM_REFERENCE_KIND_CODE, INVALID_CONSTANT_REFERENCE_STOP_CODE, @@ -167,6 +168,8 @@ def build_declaration_scope_resolver( if loaded_macros is not None: for macro in loaded_macros.values(): declarations[DeclarationIdentity(DeclarationKind.MACRO, macro.name)] = macro + if lookup is None and native_stage_enabled(NativeStage.DECLARATION_SCOPES): + report_native_fallback(site=NativeFallbackSite.SCOPE_REBIND_LOOKUP) scope_lookup: ScopeLookup = build_scope_lookup(index=scope_index) if lookup is None else lookup return DeclarationScopeResolver( project_dir=discovered_inputs.project_dir, @@ -229,6 +232,11 @@ def resolve_declaration_context( and not _scope_query_parses_identity(resource=resource, target_path=target_path) else None ) + if native_context is None and resolver.native_contexts is not None: + report_native_fallback( + site=NativeFallbackSite.DECLARATION_CONTEXT, + kind="deferred" if resources else "no_resource", + ) context: DeclarationResolutionContext = ( native_context if native_context is not None diff --git a/src/sqlbuild/compiler/compile/_helpers/render/macros.py b/src/sqlbuild/compiler/compile/_helpers/render/macros.py index f011f320a0..eb8ef33c10 100644 --- a/src/sqlbuild/compiler/compile/_helpers/render/macros.py +++ b/src/sqlbuild/compiler/compile/_helpers/render/macros.py @@ -49,6 +49,9 @@ DiscoveredMacroFile, EnumDeclaration, ) +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.macro_bridge.classes.macro_bridge import MacroBridge from sqlbuild.compiler.macro_bridge.constants import ( DECLARATION_READ_EVENT, @@ -1209,6 +1212,11 @@ def expand_sql_macros_result( consumer=consumer, ) bridge: MacroBridge | None = active_macro_bridge() if not state.macro_overrides else None + if bridge is None and MACRO_TOKEN in sql and native_stage_enabled(NativeStage.MACRO_CALLS): + report_native_fallback( + site=NativeFallbackSite.MACRO_UNBRIDGED_EXPANSION, + kind="macro_mocks" if state.macro_overrides else "outside_compile_inputs", + ) expanded_sql, spans = ( _expand_sql_macros( sql=sql, @@ -1772,6 +1780,8 @@ def _parse_macro_arguments( ) -> tuple[tuple[object, ...], dict[str, object]]: if not args_source.strip(): return (), {} + if native_stage_enabled(NativeStage.MACRO_CALLS): + report_native_fallback(site=NativeFallbackSite.MACRO_ARGUMENTS) rewritten_args_source: str placeholder_values: dict[str, object] rewritten_args_source, placeholder_values = _rewrite_nested_macro_calls( diff --git a/src/sqlbuild/compiler/compile/_helpers/render/sql_vars.py b/src/sqlbuild/compiler/compile/_helpers/render/sql_vars.py index a25848e0df..e6e19e3b0d 100644 --- a/src/sqlbuild/compiler/compile/_helpers/render/sql_vars.py +++ b/src/sqlbuild/compiler/compile/_helpers/render/sql_vars.py @@ -38,7 +38,8 @@ ) from sqlbuild.compiler.compile.types import TypedSqlValueRenderer from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.model_loop.main._scan_native_declaration_references import ( scan_native_declaration_references, ) @@ -116,6 +117,8 @@ def expand_authored_sql_result( # noqa: PLR0913 if native else None ) + if native and scanned_result is None: + report_native_fallback(site=NativeFallbackSite.DECLARATION_REFERENCES, kind="scan") declaration_result: DeclarationExpansionResult = ( scanned_result if scanned_result is not None @@ -227,6 +230,7 @@ def prepare_static_project_vars_batch( if not isinstance(raw_results, list) or len(raw_results) != len(sqls): raise CompileInputError("native static SQL interpolation returned an invalid batch") results: list[str | None] = [] + counted: bool = native_stage_enabled(NativeStage.MODEL_LOOP) for sql, raw_result in zip(sqls, raw_results, strict=True): if not ( isinstance(raw_result, tuple) @@ -241,6 +245,8 @@ def prepare_static_project_vars_batch( elif status == _NATIVE_SUBSTITUTED and rendered is not None: results.append(rendered) elif status == _NATIVE_FALLBACK and rendered is None: + if counted: + report_native_fallback(site=NativeFallbackSite.SQL_VARIABLES) results.append(None) elif status in _NATIVE_ERROR_STATUSES: if error_file_path is not None: @@ -250,6 +256,8 @@ def prepare_static_project_vars_batch( file_path=error_file_path, effective_vars=effective_vars, ) + if counted: + report_native_fallback(site=NativeFallbackSite.SQL_VARIABLES, kind="error") results.append(None) else: raise CompileInputError("native static SQL interpolation returned an invalid status") diff --git a/src/sqlbuild/compiler/compile/_helpers/scenarios/core.py b/src/sqlbuild/compiler/compile/_helpers/scenarios/core.py index 40e81b2b60..11682b900c 100644 --- a/src/sqlbuild/compiler/compile/_helpers/scenarios/core.py +++ b/src/sqlbuild/compiler/compile/_helpers/scenarios/core.py @@ -30,7 +30,9 @@ CompileSqlScenarioCtes, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.sql_analysis.models import SqlLexicalSyntax _CONTEXT: str = "SQL scenario" @@ -50,7 +52,10 @@ def extract_sql_scenario_ctes( else None ) if native_ctes is not None: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="scenario_ctes") return native_ctes + if native_stage_enabled(NativeStage.ATTACHMENTS): + report_native_fallback(site=NativeFallbackSite.SCENARIO_CTES) ctes: tuple[CompileSqlScenarioCte, ...] = extract_top_level_ctes_with_scanner( sql=sql, file_label=file_label, @@ -91,6 +96,7 @@ def _scenario_from_native_outcome( independence: list[list[str]] | None = outcome.get("independence") if independence is not None: + report_native_fallback(site=NativeFallbackSite.SCENARIO_INDEPENDENCE) validate_independent_expected_and_assertion_ctes( ctes=_scenario_ctes(independence), expected_prefix=EXPECTED_TEST_CTE_PREFIX, diff --git a/src/sqlbuild/compiler/compile/_helpers/sql_tests/core.py b/src/sqlbuild/compiler/compile/_helpers/sql_tests/core.py index 47a41fee26..4157dd2385 100644 --- a/src/sqlbuild/compiler/compile/_helpers/sql_tests/core.py +++ b/src/sqlbuild/compiler/compile/_helpers/sql_tests/core.py @@ -30,7 +30,9 @@ omitted_ceremonial_select_offset, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled -from sqlbuild.compiler.frontier.types import NativeStage +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.references.types import SqlReferenceKind from sqlbuild.compiler.sql_analysis.main._find_matching_paren import find_matching_paren from sqlbuild.compiler.sql_analysis.main._is_identifier_character import ( @@ -157,7 +159,11 @@ def complete_omitted_ceremonial_select(*, sql: str, syntax: SqlLexicalSyntax) -> if native_stage_enabled(NativeStage.ATTACHMENTS) else (False, None) ) - if not answered: + if answered: + report_native_answer(stage=NativeStage.ATTACHMENTS, kind="omitted_select_scans") + else: + if native_stage_enabled(NativeStage.ATTACHMENTS): + report_native_fallback(site=NativeFallbackSite.OMITTED_SELECT) offset = omitted_ceremonial_select_offset(sql=sql, syntax=syntax) if offset is None: return sql diff --git a/src/sqlbuild/compiler/compile/_helpers/sql_tests/scope_deps.py b/src/sqlbuild/compiler/compile/_helpers/sql_tests/scope_deps.py new file mode 100644 index 0000000000..38463bfeae --- /dev/null +++ b/src/sqlbuild/compiler/compile/_helpers/sql_tests/scope_deps.py @@ -0,0 +1,67 @@ +"""Scope dependencies of macro, UDF and table-function SQL tests.""" + +from __future__ import annotations + +from sqlbuild.compiler.compile._helpers.render.macros import find_macro_call_names +from sqlbuild.compiler.compile.models import CompiledObjectKey, CompileModelInput +from sqlbuild.compiler.compile.types import CompiledResourceType +from sqlbuild.compiler.references.types import SqlReferenceKind + + +def macro_sql_test_scope_deps( + *, tested_macro_names: tuple[str, ...], model_inputs: tuple[CompileModelInput, ...] +) -> tuple[CompiledObjectKey, ...]: + """Return the models whose macro calls include a tested macro.""" + + tested_names: frozenset[str] = frozenset(tested_macro_names) + scope_deps: list[CompiledObjectKey] = [] + model_input: CompileModelInput + for model_input in model_inputs: + model_macro_deps: frozenset[str] = frozenset( + model_input.macro_deps or find_macro_call_names(model_input.macro_source_sql) + ) + if not tested_names.intersection(model_macro_deps): + continue + scope_deps.append( + CompiledObjectKey( + resource_type=CompiledResourceType.MODEL, + name=model_input.model_file.file_path.stem, + ) + ) + return tuple(scope_deps) + + +def udf_sql_test_scope_deps( + *, tested_udf_names: tuple[str, ...], model_inputs: tuple[CompileModelInput, ...] +) -> tuple[CompiledObjectKey, ...]: + """Return the models that call a tested UDF.""" + + tested_names: frozenset[str] = frozenset(tested_udf_names) + scope_deps: list[CompiledObjectKey] = [] + model_input: CompileModelInput + for model_input in model_inputs: + model_udf_deps: frozenset[str] = frozenset( + reference.ref_name + for reference in model_input.references + if reference.ref_kind == SqlReferenceKind.UDF + ) + if not tested_names.intersection(model_udf_deps): + continue + scope_deps.append( + CompiledObjectKey( + resource_type=CompiledResourceType.MODEL, + name=model_input.model_file.file_path.stem, + ) + ) + return tuple(scope_deps) + + +def function_sql_test_scope_deps( + *, tested_function_names: tuple[str, ...] +) -> tuple[CompiledObjectKey, ...]: + """Return the tested table functions as scope dependencies.""" + + return tuple( + CompiledObjectKey(resource_type=CompiledResourceType.TABLE_FN, name=function_name) + for function_name in tested_function_names + ) diff --git a/src/sqlbuild/compiler/compile/main/expand_sql_with_spans.py b/src/sqlbuild/compiler/compile/main/expand_sql_with_spans.py index ec9f8da08e..2b1771d007 100644 --- a/src/sqlbuild/compiler/compile/main/expand_sql_with_spans.py +++ b/src/sqlbuild/compiler/compile/main/expand_sql_with_spans.py @@ -11,6 +11,9 @@ ExpansionSpan, SqlExpansionContext, ) +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage def expand_sql_with_spans( @@ -36,6 +39,8 @@ def expand_sql_with_spans( inaccessible_enums=declarations.inaccessible_enums, inaccessible_constants=declarations.inaccessible_constants, ) + if native_stage_enabled(NativeStage.MODEL_LOOP): + report_native_fallback(site=NativeFallbackSite.LINT_EXPANSION) return expand_authored_sql_with_spans( sql=sql, file_path=file_path, diff --git a/src/sqlbuild/compiler/compile/main/expand_template_data.py b/src/sqlbuild/compiler/compile/main/expand_template_data.py index cd173d3d2f..ac93265bdf 100644 --- a/src/sqlbuild/compiler/compile/main/expand_template_data.py +++ b/src/sqlbuild/compiler/compile/main/expand_template_data.py @@ -5,6 +5,9 @@ from sqlbuild.compiler.compile._helpers.render.templating import ( expand_template_data as _expand_template_data, ) +from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage def expand_template_data( @@ -19,6 +22,8 @@ def expand_template_data( ) -> object: """Recursively expand template strings inside supported Python container values.""" + if native_stage_enabled(NativeStage.MODEL_CONFIG): + report_native_fallback(site=NativeFallbackSite.PYTHON_TEMPLATES, kind="api") return _expand_template_data( value=value, variables=variables, diff --git a/src/sqlbuild/compiler/contracts/main/promotion_conflicts.py b/src/sqlbuild/compiler/contracts/main/promotion_conflicts.py index 5e86bbab99..33edbfd775 100644 --- a/src/sqlbuild/compiler/contracts/main/promotion_conflicts.py +++ b/src/sqlbuild/compiler/contracts/main/promotion_conflicts.py @@ -9,6 +9,7 @@ native_promotion_conflict_diagnostics, ) from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer from sqlbuild.compiler.frontier.types import NativeStage @@ -25,6 +26,7 @@ def promotion_conflict_diagnostics( project=project, adapter_default=adapter_default, settings_file=settings_file ) if native is not None: + report_native_answer(stage=NativeStage.CONTRACTS, kind="promotion_checks") return native return promotion_conflict_diagnostics_impl( project=project, adapter_default=adapter_default, settings_file=settings_file diff --git a/src/sqlbuild/compiler/contracts/main/validate.py b/src/sqlbuild/compiler/contracts/main/validate.py index a3ea86bee3..a51a6dda3b 100644 --- a/src/sqlbuild/compiler/contracts/main/validate.py +++ b/src/sqlbuild/compiler/contracts/main/validate.py @@ -13,6 +13,7 @@ ) from sqlbuild.compiler.contracts.models import ContractValidationResult from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer from sqlbuild.compiler.frontier.types import NativeStage from sqlbuild.spec.contracts.types import ColumnContractMode @@ -29,6 +30,7 @@ def evaluate_model_contracts( project=project, dialect=dialect ) if native_result is not None: + report_native_answer(stage=NativeStage.CONTRACTS, kind="contract_validations") return native_result mode: ColumnContractMode = project.settings.column_contract_mode if not any(requires_contract_evaluation(model=model, mode=mode) for model in project.models): diff --git a/src/sqlbuild/compiler/discovery/_helpers/native/declaration_files.py b/src/sqlbuild/compiler/discovery/_helpers/native/declaration_files.py index 3316b96fe2..b7bdf895a6 100644 --- a/src/sqlbuild/compiler/discovery/_helpers/native/declaration_files.py +++ b/src/sqlbuild/compiler/discovery/_helpers/native/declaration_files.py @@ -49,6 +49,9 @@ ModelSchemaDeclaration, ) from sqlbuild.compiler.discovery.types import NativeFileScope, NativeLocation, NativeScopeFields +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.scopes.types import DeclarationKind, ScopeKind type _NativeDeclarationFile = tuple[str, NativeFileScope | None, tuple[object, ...]] @@ -188,10 +191,12 @@ def native_macro_files( def native_seed_files(*, project_dir: Path) -> tuple[DiscoveredSeedFile, ...]: """Discover the seed files natively.""" - return tuple( + seeds: tuple[DiscoveredSeedFile, ...] = tuple( DiscoveredSeedFile(file_path=project_dir / relative_path, relative_path=Path(relative_path)) for relative_path, _scope, _payload in _native_files(project_dir=project_dir, kind="seed") ) + report_native_answer(stage=NativeStage.DECLARATION_FILES, kind="seed_files", units=len(seeds)) + return seeds def retained_discovery_session(*, project_dir: Path) -> _native.NativeDiscoverySession | None: @@ -274,12 +279,15 @@ def _record[RecordT]( scope, payload = item tag: object = payload[0] if tag == NATIVE_DEFERRED_TAG: + report_native_fallback(site=NativeFallbackSite.DECLARATION_FILE) return parse_with_python(relative_path=relative_path, scope=scope) if tag == NATIVE_PARSED_TAG: + report_native_answer(stage=NativeStage.DECLARATION_FILES, kind="parsed_files") return build( project_dir=project_dir, relative_path=relative_path, scope=scope, payload=payload ) if tag == NATIVE_FAILED_TAG: + report_native_answer(stage=NativeStage.DECLARATION_FILES, kind="failed_files") raise native_failure(payload) raise native_read_error(payload=payload, file_path=project_dir / relative_path) diff --git a/src/sqlbuild/compiler/discovery/_helpers/native/model_files.py b/src/sqlbuild/compiler/discovery/_helpers/native/model_files.py index 4c166f2493..ee78a71c88 100644 --- a/src/sqlbuild/compiler/discovery/_helpers/native/model_files.py +++ b/src/sqlbuild/compiler/discovery/_helpers/native/model_files.py @@ -28,6 +28,8 @@ ) from sqlbuild.compiler.discovery.models import DiscoveredSqlModelFile, DiscoveryFileFault from sqlbuild.compiler.discovery.types import NativeFiles, NativeLocation +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.types import NativeStage def discover_native_model_files( @@ -58,6 +60,7 @@ def discover_native_model_files( project_dir=project_dir, ) seed_snapshot_listings(project_dir=project_dir, tree=tree) + report_native_answer(stage=NativeStage.DISCOVERY, kind="model_file_listings") return materialise_native_files( project_dir=project_dir, files=( diff --git a/src/sqlbuild/compiler/frontier/_helpers/process_recorder.py b/src/sqlbuild/compiler/frontier/_helpers/process_recorder.py new file mode 100644 index 0000000000..37f53b4700 --- /dev/null +++ b/src/sqlbuild/compiler/frontier/_helpers/process_recorder.py @@ -0,0 +1,12 @@ +"""The process's debug recorder of native fallbacks and answers, created once.""" + +from functools import cache + +from sqlbuild.compiler.frontier.classes.native_fallback_recorder import NativeFallbackRecorder + + +@cache +def process_recorder() -> NativeFallbackRecorder | None: + """Return the recorder when the debug record directory is set, otherwise None.""" + + return NativeFallbackRecorder.from_environment() diff --git a/src/sqlbuild/compiler/frontier/classes/native_fallback_recorder.py b/src/sqlbuild/compiler/frontier/classes/native_fallback_recorder.py new file mode 100644 index 0000000000..270c533694 --- /dev/null +++ b/src/sqlbuild/compiler/frontier/classes/native_fallback_recorder.py @@ -0,0 +1,50 @@ +"""Debug-only count of the native fallbacks and native answers of one process, written at exit.""" + +from __future__ import annotations + +import atexit +import json +import os +import threading +from collections import Counter +from pathlib import Path + +from sqlbuild.compiler.frontier.constants import NATIVE_FALLBACK_RECORD_PREFIX +from sqlbuild.compiler.sql_analysis.constants import ANALYSIS_RECORD_DIR_ENV_VAR + + +class NativeFallbackRecorder: + """Count fallbacks and answers by `(site, kind)` and write them once, at process exit.""" + + def __init__(self, *, directory: Path) -> None: + self._directory: Path = directory + self._counts: Counter[tuple[str, str]] = Counter() + self._lock: threading.Lock = threading.Lock() + _ = atexit.register(self.write) + + @classmethod + def from_environment(cls) -> NativeFallbackRecorder | None: + """Return a recorder when the debug record directory is set, otherwise None.""" + + directory: str | None = os.environ.get(ANALYSIS_RECORD_DIR_ENV_VAR) + return cls(directory=Path(directory)) if directory else None + + def record(self, *, site: str, kind: str, units: int = 1) -> None: + """Count `units` fallbacks or answers at `site` of the sort `kind`.""" + + with self._lock: + self._counts[(site, kind)] += units + + def write(self) -> None: + """Write the counts so far as `{"fallbacks": [[site, kind, count], ...]}`; none, no file.""" + + with self._lock: + counts: Counter[tuple[str, str]] = self._counts.copy() + if not counts: + return + self._directory.mkdir(parents=True, exist_ok=True) + rows: list[list[object]] = [ + [site, kind, count] for (site, kind), count in sorted(counts.items()) + ] + target: Path = self._directory / f"{NATIVE_FALLBACK_RECORD_PREFIX}{os.getpid()}.json" + _ = target.write_text(json.dumps({"fallbacks": rows}) + "\n", encoding="utf-8") diff --git a/src/sqlbuild/compiler/frontier/constants.py b/src/sqlbuild/compiler/frontier/constants.py index 195b5404c3..cd1adcea0d 100644 --- a/src/sqlbuild/compiler/frontier/constants.py +++ b/src/sqlbuild/compiler/frontier/constants.py @@ -41,6 +41,9 @@ TARGET_DIRECTORY_NAME: str = "target" CACHE_DIRECTORY_NAME: str = "cache" COMPILER_CACHE_DIRECTORY_NAME: str = "compiler" +NATIVE_FALLBACK_RECORD_PREFIX: str = "native-fallbacks-" +NATIVE_FALLBACK_DEFAULT_KIND: str = "deferred" +NATIVE_ANSWER_SITE_SUFFIX: str = ".native" STAGE_CAPTURE_DIR_ENV_VAR: str = "SQLBUILD_COMPILER_STAGE_CAPTURE_DIR" COMPILE_REUSE_DISABLE_ENV_VAR: str = "SQLBUILD_DISABLE_COMPILE_REUSE" STAGE_CAPTURE_SUFFIX: str = ".json" diff --git a/src/sqlbuild/compiler/frontier/main/report_native_answer.py b/src/sqlbuild/compiler/frontier/main/report_native_answer.py new file mode 100644 index 0000000000..4acc7b2f00 --- /dev/null +++ b/src/sqlbuild/compiler/frontier/main/report_native_answer.py @@ -0,0 +1,14 @@ +"""Count work a native stage answered itself, so a stage switched to Python is noticed.""" + +from sqlbuild.compiler.frontier._helpers.process_recorder import process_recorder +from sqlbuild.compiler.frontier.classes.native_fallback_recorder import NativeFallbackRecorder +from sqlbuild.compiler.frontier.constants import NATIVE_ANSWER_SITE_SUFFIX +from sqlbuild.compiler.frontier.types import NativeStage + + +def report_native_answer(*, stage: NativeStage, kind: str, units: int = 1) -> None: + """Record `units` of work of the sort `kind` that `stage` answered natively, when recording.""" + + recorder: NativeFallbackRecorder | None = process_recorder() + if recorder is not None and units: + recorder.record(site=f"{stage.value}{NATIVE_ANSWER_SITE_SUFFIX}", kind=kind, units=units) diff --git a/src/sqlbuild/compiler/frontier/main/report_native_fallback.py b/src/sqlbuild/compiler/frontier/main/report_native_fallback.py new file mode 100644 index 0000000000..8c2f0ba101 --- /dev/null +++ b/src/sqlbuild/compiler/frontier/main/report_native_fallback.py @@ -0,0 +1,16 @@ +"""Count one place where a native stage handed its work back to Python.""" + +from sqlbuild.compiler.frontier._helpers.process_recorder import process_recorder +from sqlbuild.compiler.frontier.classes.native_fallback_recorder import NativeFallbackRecorder +from sqlbuild.compiler.frontier.constants import NATIVE_FALLBACK_DEFAULT_KIND +from sqlbuild.compiler.frontier.types import NativeFallbackSite + + +def report_native_fallback( + *, site: NativeFallbackSite, kind: str = NATIVE_FALLBACK_DEFAULT_KIND +) -> None: + """Record a fallback at `site` when the debug record directory is set; otherwise do nothing.""" + + recorder: NativeFallbackRecorder | None = process_recorder() + if recorder is not None: + recorder.record(site=site.value, kind=kind) diff --git a/src/sqlbuild/compiler/frontier/types.py b/src/sqlbuild/compiler/frontier/types.py index 17b611e46f..e3e38174ff 100644 --- a/src/sqlbuild/compiler/frontier/types.py +++ b/src/sqlbuild/compiler/frontier/types.py @@ -45,3 +45,42 @@ class CompilerStage(StrEnum): DISCOVERED_PROJECT_INPUTS = "discovered_project_inputs" COMPILE_PROJECT_INPUTS = "compile_project_inputs" COMPILED_PROJECT = "compiled_project" + + +class NativeFallbackSite(StrEnum): + """A place where a shipped native stage still hands its work to the Python implementation.""" + + DECLARATION_FILE = "declaration_files.file" + SCOPE_INDEX = "declaration_scopes.index" + SCOPE_GRANTS = "declaration_scopes.grants" + SCOPE_LOOKUP = "declaration_scopes.lookup" + SCOPE_REBIND_LOOKUP = "declaration_scopes.rebind_lookup" + SCOPE_RELATIONSHIP_CTES = "declaration_scopes.relationship_ctes" + SQL_VARIABLES = "model_loop.sql_variables" + DECLARATION_REFERENCES = "model_loop.declaration_references" + DECLARATION_CONTEXT = "model_loop.declaration_context" + CURSOR_INTRINSIC_VALIDATION = "model_loop.cursor_intrinsic_validation" + LINT_EXPANSION = "model_loop.lint_expansion" + MACRO_CALL_SCAN = "macro_calls.scan" + MACRO_CALL_RESOLUTION = "macro_calls.resolution" + MACRO_CALL_SPLICE = "macro_calls.splice" + MACRO_CALL_MEMO = "macro_calls.memo" + MACRO_ARGUMENTS = "macro_calls.arguments" + MACRO_UNBRIDGED_EXPANSION = "macro_calls.unbridged_expansion" + MACRO_BRIDGE_UNAVAILABLE = "macro_calls.bridge_unavailable" + REFERENCE_SCAN = "reference_extraction.scan" + CONFIG_BUILD = "model_config.build" + CONFIG_HEADER_METADATA = "model_config.header_metadata" + CONFIG_TEMPLATES = "model_config.templates" + CONFIG_PRESENCE_SCAN = "model_config.presence_scan" + CONFIG_VALIDATORS = "model_config.validators" + PYTHON_TEMPLATES = "model_config.python_templates" + AUDIT_RENDERING = "attachments.audit_rendering" + FUNCTION_HEADER = "attachments.function_header" + CURSOR_INTRINSIC_REJECTION = "attachments.cursor_intrinsic_rejection" + SCENARIO_CTES = "attachments.scenario_ctes" + SCENARIO_INDEPENDENCE = "attachments.scenario_independence" + OMITTED_SELECT = "attachments.omitted_select" + PROJECT_ASSEMBLY = "project_assembly.assembly" + TYPE_NORMALIZATION = "type_system.normalization" + SQL_TEST_ASSEMBLY = "sql_test_glue.assembly" diff --git a/src/sqlbuild/compiler/lineage/main/columns.py b/src/sqlbuild/compiler/lineage/main/columns.py index fc44eab5bc..735a03c3d2 100644 --- a/src/sqlbuild/compiler/lineage/main/columns.py +++ b/src/sqlbuild/compiler/lineage/main/columns.py @@ -4,6 +4,7 @@ from sqlbuild.compiler.compile.models import CompiledProject from sqlbuild.compiler.frontier.main.native_stage_enabled import native_stage_enabled +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer from sqlbuild.compiler.frontier.types import NativeStage from sqlbuild.compiler.lineage._helpers.fast_columns import ( build_fast_project_column_lineage, @@ -34,6 +35,7 @@ def build_project_column_lineage( project=project, dialect=dialect, model_names=model_names ) if native_lineage is not None: + report_native_answer(stage=NativeStage.LINEAGE_FACTS, kind="lineage_graphs") return native_lineage return build_fast_project_column_lineage( project=project, diff --git a/src/sqlbuild/compiler/macro_bridge/classes/macro_bridge.py b/src/sqlbuild/compiler/macro_bridge/classes/macro_bridge.py index 731fe2ca5b..2ee2d9cf15 100644 --- a/src/sqlbuild/compiler/macro_bridge/classes/macro_bridge.py +++ b/src/sqlbuild/compiler/macro_bridge/classes/macro_bridge.py @@ -14,6 +14,8 @@ LoadedMacro, MacroContext, ) +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite from sqlbuild.compiler.macro_bridge._helpers.splicing import splice_text from sqlbuild.compiler.macro_bridge._helpers.store_environment import ( digest_module_files, @@ -139,8 +141,10 @@ def scan(self, sql: str) -> tuple[MacroCallSite, ...] | None: _native.scan_macro_call_sites(sql, self._python_version, self._unicode_version) ) except UnicodeEncodeError: + report_native_fallback(site=NativeFallbackSite.MACRO_CALL_SCAN, kind="unencodable") return None if rows is None: + report_native_fallback(site=NativeFallbackSite.MACRO_CALL_SCAN) return None return tuple( MacroCallSite( @@ -258,6 +262,7 @@ def record( ), ) except UnicodeEncodeError: + report_native_fallback(site=NativeFallbackSite.MACRO_CALL_MEMO, kind="unencodable") return def splice( @@ -271,6 +276,7 @@ def splice( try: rendered, spans = _native.splice_macro_calls(sql, bounds, outputs) except UnicodeEncodeError: + report_native_fallback(site=NativeFallbackSite.MACRO_CALL_SPLICE, kind="unencodable") rendered, spans = splice_text(sql=sql, bounds=bounds, outputs=outputs) return rendered, tuple( ExpansionSpan( diff --git a/src/sqlbuild/compiler/macro_bridge/main/run_with_macro_bridge.py b/src/sqlbuild/compiler/macro_bridge/main/run_with_macro_bridge.py index fcaa59d694..1d53c9869c 100644 --- a/src/sqlbuild/compiler/macro_bridge/main/run_with_macro_bridge.py +++ b/src/sqlbuild/compiler/macro_bridge/main/run_with_macro_bridge.py @@ -9,6 +9,9 @@ from contextvars import Token import sqlbuild._native as _native +from sqlbuild.compiler.frontier.main.report_native_answer import report_native_answer +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite, NativeStage from sqlbuild.compiler.macro_bridge.classes.macro_bridge import MacroBridge from sqlbuild.compiler.macro_bridge.constants import ACTIVE_MACRO_BRIDGE, STORE_MODULE_PATHS @@ -18,6 +21,7 @@ def run_with_macro_bridge[T](*, stage: Callable[[], T]) -> T: python_version: tuple[int, int] = (sys.version_info[0], sys.version_info[1]) if not _native.native_text_supported(python_version, unicodedata.unidata_version): + report_native_fallback(site=NativeFallbackSite.MACRO_BRIDGE_UNAVAILABLE) return stage() bridge: MacroBridge = MacroBridge( python_version=python_version, unicode_version=unicodedata.unidata_version @@ -31,6 +35,7 @@ def run_with_macro_bridge[T](*, stage: Callable[[], T]) -> T: STORE_MODULE_PATHS.update(bridge.store_module_paths()) hits, misses, recorded = bridge.stats() store_hits, store_records = bridge.store_stats() + report_native_answer(stage=NativeStage.MACRO_CALL_STORE, kind="served_calls", units=store_hits) logging.getLogger(__name__).debug( "Native macro bridge: %d memo hits, %d store hits, %d misses, %d recorded calls, " "%d stored calls", diff --git a/src/sqlbuild/compiler/model_config/main/_parse_native_header_metadata.py b/src/sqlbuild/compiler/model_config/main/_parse_native_header_metadata.py index 6314d37b52..cc35ecbd20 100644 --- a/src/sqlbuild/compiler/model_config/main/_parse_native_header_metadata.py +++ b/src/sqlbuild/compiler/model_config/main/_parse_native_header_metadata.py @@ -9,6 +9,8 @@ import sqlbuild._native as _native from sqlbuild.compiler.auditing.types import AuditSeverity from sqlbuild.compiler.discovery.models import DiscoveredSqlModelFile +from sqlbuild.compiler.frontier.main.report_native_fallback import report_native_fallback +from sqlbuild.compiler.frontier.types import NativeFallbackSite from sqlbuild.compiler.model_config.constants import ( AUDITS_HEADER_KEY, COLUMNS_HEADER_KEY, @@ -47,7 +49,13 @@ def parse_native_header_metadata( }, ) except (TypeError, ValueError): + report_native_fallback(site=NativeFallbackSite.CONFIG_HEADER_METADATA, kind="batch") return {} + for metadata in parsed: + if metadata == UNSUPPORTED_OUTCOME: + report_native_fallback( + site=NativeFallbackSite.CONFIG_HEADER_METADATA, kind="unsupported" + ) return { model_file.file_path: _native_metadata(model_file=model_file, metadata=metadata) for model_file, metadata in zip(model_files, parsed, strict=True) diff --git a/src/sqlbuild/compiler/profiling/_helpers/__init__.py b/src/sqlbuild/compiler/profiling/_helpers/__init__.py new file mode 100644 index 0000000000..64fb62aa62 --- /dev/null +++ b/src/sqlbuild/compiler/profiling/_helpers/__init__.py @@ -0,0 +1 @@ +"""Native model analysis session helpers.""" diff --git a/src/sqlbuild/compiler/profiling/_helpers/timing.py b/src/sqlbuild/compiler/profiling/_helpers/timing.py new file mode 100644 index 0000000000..42ccefd697 --- /dev/null +++ b/src/sqlbuild/compiler/profiling/_helpers/timing.py @@ -0,0 +1,23 @@ +"""Compile phase timing by a chosen clock.""" + +from collections.abc import Callable, Iterator +from contextlib import contextmanager + +from sqlbuild.compiler.profiling.classes.context import CompileTimingContext +from sqlbuild.compiler.profiling.models import CompileTimingCollector +from sqlbuild.compiler.profiling.types import CompileTimingPhase + + +@contextmanager +def recorded_timing(*, phase: CompileTimingPhase, clock: Callable[[], int]) -> Iterator[None]: + """Record an operation by `clock` when a compile timing collector is active.""" + + collector: CompileTimingCollector | None = CompileTimingContext.active.get() + if collector is None: + yield + return + start_ns: int = clock() + try: + yield + finally: + collector.add(phase=phase, elapsed_ns=clock() - start_ns) diff --git a/src/sqlbuild/compiler/profiling/constants.py b/src/sqlbuild/compiler/profiling/constants.py index 1ff96dd869..7cf606a237 100644 --- a/src/sqlbuild/compiler/profiling/constants.py +++ b/src/sqlbuild/compiler/profiling/constants.py @@ -5,6 +5,7 @@ COMPILE_TIMING_PHASES: tuple[CompileTimingPhase, ...] = ( "attachment_ms", "model_analysis_ms", + "model_analysis_cpu_ms", "analysis_preparation_ms", "analysis_native_ms", "analysis_projection_ms", diff --git a/src/sqlbuild/compiler/profiling/main/_record_cpu.py b/src/sqlbuild/compiler/profiling/main/_record_cpu.py new file mode 100644 index 0000000000..a0a15e0ef7 --- /dev/null +++ b/src/sqlbuild/compiler/profiling/main/_record_cpu.py @@ -0,0 +1,13 @@ +"""Compile phase CPU recording entry point.""" + +import time +from contextlib import AbstractContextManager + +from sqlbuild.compiler.profiling._helpers.timing import recorded_timing +from sqlbuild.compiler.profiling.types import CompileTimingPhase + + +def record_compile_cpu_timing(phase: CompileTimingPhase) -> AbstractContextManager[None]: + """Record the process CPU time an operation spans, including its worker threads.""" + + return recorded_timing(phase=phase, clock=time.process_time_ns) diff --git a/src/sqlbuild/compiler/profiling/main/record.py b/src/sqlbuild/compiler/profiling/main/record.py index 5518e5a413..4053321d80 100644 --- a/src/sqlbuild/compiler/profiling/main/record.py +++ b/src/sqlbuild/compiler/profiling/main/record.py @@ -1,24 +1,13 @@ """Compile phase recording entry point.""" import time -from collections.abc import Iterator -from contextlib import contextmanager +from contextlib import AbstractContextManager -from sqlbuild.compiler.profiling.classes.context import CompileTimingContext -from sqlbuild.compiler.profiling.models import CompileTimingCollector +from sqlbuild.compiler.profiling._helpers.timing import recorded_timing from sqlbuild.compiler.profiling.types import CompileTimingPhase -@contextmanager -def record_compile_timing(phase: CompileTimingPhase) -> Iterator[None]: +def record_compile_timing(phase: CompileTimingPhase) -> AbstractContextManager[None]: """Record an operation when a compile timing collector is active.""" - collector: CompileTimingCollector | None = CompileTimingContext.active.get() - if collector is None: - yield - return - start_ns: int = time.perf_counter_ns() - try: - yield - finally: - collector.add(phase=phase, elapsed_ns=time.perf_counter_ns() - start_ns) + return recorded_timing(phase=phase, clock=time.perf_counter_ns) diff --git a/src/sqlbuild/compiler/profiling/types.py b/src/sqlbuild/compiler/profiling/types.py index 22f51e54cc..59ff6ef9d8 100644 --- a/src/sqlbuild/compiler/profiling/types.py +++ b/src/sqlbuild/compiler/profiling/types.py @@ -5,6 +5,7 @@ type CompileTimingPhase = Literal[ "attachment_ms", "model_analysis_ms", + "model_analysis_cpu_ms", "analysis_preparation_ms", "analysis_native_ms", "analysis_projection_ms", diff --git a/src/sqlbuild/compiler/project_assembly/main/_check_native_sql_syntax.py b/src/sqlbuild/compiler/project_assembly/main/_check_native_sql_syntax.py new file mode 100644 index 0000000000..a929ed239f --- /dev/null +++ b/src/sqlbuild/compiler/project_assembly/main/_check_native_sql_syntax.py @@ -0,0 +1,24 @@ +"""Check SQL syntax natively for the preview compiler engine.""" + +from __future__ import annotations + +import sqlbuild._native as _native +from sqlbuild.compiler.project_assembly._helpers.deferrals import record_project_assembly_deferral + + +def check_native_sql_syntax( + *, checks: tuple[tuple[str, dict[str, str] | None], ...], dialect: str | None +) -> bool | None: + """Whether Python's syntax validation accepts every `(sql, placeholders)`; None to check it.""" + + valid: bool | None + deferral: str | None + valid, deferral = _native.check_native_sql_syntax( + ( + dialect or "generic", + [(sql, list((placeholders or {}).items())) for sql, placeholders in checks], + ) + ) + if valid is None: + _ = record_project_assembly_deferral(kind=deferral or "unknown") + return valid diff --git a/src/sqlbuild/compiler/project_assembly/models.py b/src/sqlbuild/compiler/project_assembly/models.py index 8c6631c2cf..7905511275 100644 --- a/src/sqlbuild/compiler/project_assembly/models.py +++ b/src/sqlbuild/compiler/project_assembly/models.py @@ -4,7 +4,11 @@ from dataclasses import dataclass -from sqlbuild.compiler.compile.models import CompiledObjectKey, CompiledRelationLocation +from sqlbuild.compiler.compile.models import ( + CompiledObjectKey, + CompiledRelationLocation, + DynamicColumnContractProof, +) from sqlbuild.spec.contracts.models import SourceEntry @@ -17,3 +21,19 @@ class NativeProjectResources: seed_destinations: tuple[CompiledRelationLocation, ...] function_deps: tuple[tuple[CompiledObjectKey, ...], ...] audit_scope_deps: tuple[tuple[CompiledObjectKey, ...], ...] + + +@dataclass(frozen=True, slots=True) +class NativeModelFacts: + """One model's native facts; each None where Python derives it.""" + + deps: tuple[CompiledObjectKey, ...] | None + dynamic_contract: DynamicColumnContractProof | None + + +@dataclass(frozen=True, slots=True) +class NativeProjectFacts: + """Every model's native facts, and the resource facts unless Python must assemble them.""" + + models: tuple[NativeModelFacts, ...] + resources: NativeProjectResources | None diff --git a/src/sqlbuild/compiler/semantic_checks/_helpers/completion.py b/src/sqlbuild/compiler/semantic_checks/_helpers/completion.py index a54b887900..8afb26b9d3 100644 --- a/src/sqlbuild/compiler/semantic_checks/_helpers/completion.py +++ b/src/sqlbuild/compiler/semantic_checks/_helpers/completion.py @@ -28,7 +28,11 @@ def complete_native_diagnostics( - *, project: CompiledProject, catalog: object + *, + project: CompiledProject, + catalog: object, + session: Any | None, + session_models: frozenset[str], ) -> CompiledProject | None: """Return the recovered, explained and opt-out-checked project, or None to use Python.""" @@ -40,10 +44,15 @@ def complete_native_diagnostics( request: Any = ( project.sql_analysis_dialect, [_diagnostic_payload(item=item, ids=ids) for item in project.diagnostics], - [_model_payload(model=model, lineage=recovers) for model in project.models], + [ + _model_payload(model=model, lineage=recovers, from_session=model.name in session_models) + for model in project.models + ], [(name, list(columns.items())) for name, columns in shapes.items()], ) - deferral, completed, model_bindings, order = _native.complete_semantic_checks(catalog, request) + deferral, completed, model_bindings, order = _native.complete_semantic_checks( + catalog, request, session + ) if deferral is not None: record_semantic_deferral(kind=deferral, site=COMPLETION_DEFERRAL_SITE) return None @@ -98,14 +107,14 @@ def _diagnostic_payload( ) -def _model_payload(*, model: CompiledModel, lineage: bool) -> tuple[Any, ...]: +def _model_payload(*, model: CompiledModel, lineage: bool, from_session: bool) -> tuple[Any, ...]: opt_out: SourceLocation | None = model.rejected_sql_analysis_opt_out return ( model.name, model.query_sql, model.authored_sql, - [column.name for column in model.inferred_columns or ()], - lineage_payload(model) if lineage else [], + None if from_session else [column.name for column in model.inferred_columns or ()], + _lineage(model=model, lineage=lineage, from_session=from_session), [item.code for item in model.binding_diagnostics], None if opt_out is None else opt_out.path.name, ) @@ -151,3 +160,15 @@ def _opt_out( notes=(note,), help=help_text, ) + + +def _lineage( + *, model: CompiledModel, lineage: bool, from_session: bool +) -> list[tuple[str, list[tuple[str, str]]]] | None: + """The model's lineage rows; None asks for the session's, and only recovery reads them.""" + + if not lineage: + return [] + if from_session: + return None + return lineage_payload(model) diff --git a/src/sqlbuild/compiler/semantic_checks/_helpers/payloads.py b/src/sqlbuild/compiler/semantic_checks/_helpers/payloads.py index b05811fc97..76d8e40a60 100644 --- a/src/sqlbuild/compiler/semantic_checks/_helpers/payloads.py +++ b/src/sqlbuild/compiler/semantic_checks/_helpers/payloads.py @@ -2,11 +2,14 @@ from __future__ import annotations +from typing import Any, cast + from sqlbuild.compiler.compile.models import ( CompiledLineageColumnFact, CompiledModel, CompiledProject, CompilerDiagnostic, + DynamicColumnContractProof, ) from sqlbuild.compiler.sql_analysis.models import SqlBindingDiagnostic @@ -17,6 +20,25 @@ def lineage_payload(model: CompiledModel) -> list[tuple[str, list[tuple[str, str return [_output_payload(output) for output in model.fast_lineage_columns or ()] +def session_fact_models(*, project: CompiledProject, session: Any | None) -> frozenset[str]: + """Models whose output names and lineage are the finished session's, so need no payload.""" + + if session is None: + return frozenset() + kept: frozenset[str] = frozenset(cast(list[str], session.fact_models)) + return frozenset( + model.name + for model in project.models + if model.name in kept and not _output_proven(model.dynamic_column_contract) + ) + + +def _output_proven(proof: DynamicColumnContractProof | None) -> bool: + """Whether a dynamic proof replaced the analysed output names.""" + + return proof is not None and proof.output_proven + + def _output_payload(output: CompiledLineageColumnFact) -> tuple[str, list[tuple[str, str]]]: return ( output.output_column, diff --git a/src/sqlbuild/compiler/semantic_checks/_helpers/stage.py b/src/sqlbuild/compiler/semantic_checks/_helpers/stage.py index 1468d8c319..922ca72ff2 100644 --- a/src/sqlbuild/compiler/semantic_checks/_helpers/stage.py +++ b/src/sqlbuild/compiler/semantic_checks/_helpers/stage.py @@ -3,6 +3,7 @@ from __future__ import annotations from dataclasses import replace +from typing import Any from sqlbuild.adapter.contract.models import ExpressionInferenceProfile from sqlbuild.compiler.compile.classes.semantic_completion_inputs import SemanticCompletionInputs @@ -10,6 +11,7 @@ from sqlbuild.compiler.semantic_checks._helpers.completion import complete_native_diagnostics from sqlbuild.compiler.semantic_checks._helpers.deferrals import record_semantic_deferral from sqlbuild.compiler.semantic_checks._helpers.metadata import native_metadata_diagnostics +from sqlbuild.compiler.semantic_checks._helpers.payloads import session_fact_models from sqlbuild.compiler.semantic_checks._helpers.type_recovery import recover_native_output_types from sqlbuild.compiler.semantic_checks.constants import ( COMPLETION_DEFERRAL_SITE, @@ -24,6 +26,7 @@ def completed_semantic_project( profile: ExpressionInferenceProfile, binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]], resource_sql_analysis: bool, + session: Any | None, ) -> CompiledProject | None: """Python's completed project, or None where any native step hands the stage back.""" @@ -31,8 +34,13 @@ def completed_semantic_project( record_semantic_deferral(kind=NATIVE_SEMANTIC_NO_CATALOG, site=COMPLETION_DEFERRAL_SITE) return None catalog: object = project.binding_catalog.native + session_models: frozenset[str] = session_fact_models(project=project, session=session) recovered: CompiledProject | None = recover_native_output_types( - project=project, binding_results=binding_results, catalog=catalog + project=project, + binding_results=binding_results, + catalog=catalog, + session=session, + session_models=session_models, ) if recovered is None: return None @@ -49,4 +57,6 @@ def completed_semantic_project( return complete_native_diagnostics( project=replace(recovered, diagnostics=(*recovered.diagnostics, *metadata)), catalog=catalog, + session=session, + session_models=session_models, ) diff --git a/src/sqlbuild/compiler/semantic_checks/_helpers/type_recovery.py b/src/sqlbuild/compiler/semantic_checks/_helpers/type_recovery.py index c4ade28bdb..d433974d15 100644 --- a/src/sqlbuild/compiler/semantic_checks/_helpers/type_recovery.py +++ b/src/sqlbuild/compiler/semantic_checks/_helpers/type_recovery.py @@ -39,6 +39,8 @@ def recover_native_output_types( project: CompiledProject, binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]], catalog: object, + session: Any | None, + session_models: frozenset[str], ) -> CompiledProject | None: """Return `recover_output_types`'s project, or None where Python must recover the types.""" @@ -49,7 +51,13 @@ def recover_native_output_types( request: Any = ( project.sql_analysis_dialect, [ - _model_payload(model=model, binding_results=binding_results, ids=ids, raw_ids=raw_ids) + _model_payload( + model=model, + binding_results=binding_results, + ids=ids, + raw_ids=raw_ids, + from_session=model.name in session_models, + ) for model in project.models ], [ @@ -62,7 +70,9 @@ def recover_native_output_types( for item in project.diagnostics ], ) - recovery: _native.SemanticTypeRecovery = _native.plan_semantic_type_recovery(catalog, request) + recovery: _native.SemanticTypeRecovery = _native.plan_semantic_type_recovery( + catalog, request, session + ) if recovery.status == NATIVE_TYPE_RECOVERY_UNCHANGED: return project if recovery.status == NATIVE_TYPE_RECOVERY_DEFERRED: @@ -120,6 +130,7 @@ def _model_payload( binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]], ids: dict[CompilerDiagnostic, int], raw_ids: dict[SqlBindingDiagnostic, int], + from_session: bool, ) -> tuple[Any, ...]: raws: tuple[SqlBindingDiagnostic, ...] = ( binding_results.get(model.name, ()) if model.binding_diagnostics else () @@ -128,10 +139,10 @@ def _model_payload( model.name, model.query_sql, None - if model.inferred_columns is None + if from_session or model.inferred_columns is None else [column.name for column in model.inferred_columns], [reference.ref_name for reference in model.references], - lineage_payload(model), + None if from_session else lineage_payload(model), [(ids[item], item.code, item.message, item.is_error) for item in model.binding_diagnostics], [(raw_ids[raw], raw.code, raw.message, raw.start, raw.end) for raw in raws], ) diff --git a/src/sqlbuild/compiler/semantic_checks/main/_complete_native_semantic_diagnostics.py b/src/sqlbuild/compiler/semantic_checks/main/_complete_native_semantic_diagnostics.py index 762329e0a7..ca8f3e64ce 100644 --- a/src/sqlbuild/compiler/semantic_checks/main/_complete_native_semantic_diagnostics.py +++ b/src/sqlbuild/compiler/semantic_checks/main/_complete_native_semantic_diagnostics.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing import Any + from sqlbuild.adapter.contract.models import ExpressionInferenceProfile from sqlbuild.compiler.compile.models import CompiledProject from sqlbuild.compiler.semantic_checks._helpers.stage import completed_semantic_project @@ -14,6 +16,7 @@ def complete_native_semantic_diagnostics( profile: ExpressionInferenceProfile, binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]], resource_sql_analysis: bool, + session: Any | None = None, ) -> CompiledProject | None: """Return the completed project, or None where Python must complete its diagnostics.""" @@ -22,4 +25,5 @@ def complete_native_semantic_diagnostics( profile=profile, binding_results=binding_results, resource_sql_analysis=resource_sql_analysis, + session=session, ) diff --git a/src/sqlbuild/compiler/sql_test_glue/_helpers/__init__.py b/src/sqlbuild/compiler/sql_test_glue/_helpers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/sqlbuild/compiler/sql_test_glue/_helpers/assembly.py b/src/sqlbuild/compiler/sql_test_glue/_helpers/assembly.py new file mode 100644 index 0000000000..cb452078f9 --- /dev/null +++ b/src/sqlbuild/compiler/sql_test_glue/_helpers/assembly.py @@ -0,0 +1,155 @@ +"""Compiled SQL tests built from the facts the native assembly returns.""" + +from __future__ import annotations + +from pathlib import Path + +from sqlbuild.compiler.compile.constants import SQL_TEST_HELPER_REFERENCE_CODE +from sqlbuild.compiler.compile.models import ( + CompiledDirectLogicSqlTestPayload, + CompileDirectLogicSqlTestInputPayload, + CompiledModelSqlTestPayload, + CompiledObjectKey, + CompiledSqlTest, + CompiledSqlTestResource, + CompileModelSqlTestInputPayload, + CompilerDiagnostic, + CompileSqlTestInput, +) +from sqlbuild.compiler.compile.types import ( + CompiledResourceType, + DiagnosticPhase, + DiagnosticSeverity, +) +from sqlbuild.compiler.sql_test_glue._helpers.deferrals import record_sql_test_assembly_deferral +from sqlbuild.compiler.sql_test_glue.models import NativeSqlTestAssembly +from sqlbuild.compiler.sql_test_glue.types import ( + NativeSqlTestAssemblyRow, + NativeSqlTestDiagnosticRow, + NativeSqlTestFactsRow, +) +from sqlbuild.spec.contracts.models import SourceLocation + + +def native_sql_test_assemblies( + *, test_inputs: tuple[CompileSqlTestInput, ...], rows: list[NativeSqlTestAssemblyRow] +) -> tuple[NativeSqlTestAssembly | None, ...]: + """One assembly per test input, or None, recorded, where the native assembly defers.""" + + assemblies: list[NativeSqlTestAssembly | None] = [] + for test_input, (facts, deferral) in zip(test_inputs, rows, strict=True): + if facts is None: + record_sql_test_assembly_deferral(kind=str(deferral)) + assemblies.append(None) + continue + assemblies.append(native_sql_test_assembly(test_input=test_input, facts=facts)) + return tuple(assemblies) + + +def native_sql_test_assembly( + *, test_input: CompileSqlTestInput, facts: NativeSqlTestFactsRow +) -> NativeSqlTestAssembly: + """The compiled test `_assemble_compiled_sql_test` builds, from natively assembled facts.""" + + name, scope_dep_rows, target_model_names, case_fingerprint, resource_name, diagnostics = facts + scope_deps: tuple[CompiledObjectKey, ...] = tuple( + CompiledObjectKey(resource_type=resource_type, name=dep_name) + for resource_type, dep_name in scope_dep_rows + ) + payload: CompileModelSqlTestInputPayload | CompileDirectLogicSqlTestInputPayload = ( + test_input.payload + ) + compiled_payload: CompiledModelSqlTestPayload | CompiledDirectLogicSqlTestPayload + tested_resources: tuple[CompiledSqlTestResource, ...] = () + expected_model_names: tuple[str, ...] = () + assertion_names: tuple[str, ...] = () + assertion_target_model_names: tuple[str, ...] = () + read_helper_names: tuple[str, ...] = () + reference_target_model_names: tuple[str, ...] = () + if isinstance(payload, CompileDirectLogicSqlTestInputPayload): + compiled_payload = CompiledDirectLogicSqlTestPayload( + mode=payload.mode, + helper_ctes=payload.helper_ctes, + actual_cte=payload.actual_cte, + expected_cte=payload.expected_cte, + tested_resource_names=payload.tested_resource_names, + ) + tested_resources = tuple( + CompiledSqlTestResource(kind=payload.mode, name=resource_name) + for resource_name in payload.tested_resource_names + ) + else: + compiled_payload = CompiledModelSqlTestPayload( + authored_ctes=payload.authored_ctes, + macro_mocks=payload.macro_mocks, + model_query_overrides={}, + mock_model_names=payload.mock_model_names, + mock_source_names=payload.mock_source_names, + mock_seed_names=payload.mock_seed_names, + mock_dbt_ref_names=payload.mock_dbt_ref_names, + mock_table_function_names=payload.mock_table_function_names, + expected_ctes=payload.expected_ctes, + expected_model_names=payload.expected_model_names, + assertion_ctes=payload.assertion_ctes, + assertion_names=payload.assertion_names, + ) + expected_model_names = payload.expected_model_names + assertion_names = payload.assertion_names + assertion_target_model_names = payload.assertion_target_model_names + read_helper_names = payload.read_helper_names + reference_target_model_names = payload.reference_target_model_names + return NativeSqlTestAssembly( + test=CompiledSqlTest( + key=CompiledObjectKey(resource_type=CompiledResourceType.SQL_TEST, name=name), + scope_deps=scope_deps, + name=name, + test_file=test_input.test_file, + test_block=test_input.test_block, + sql_body=test_input.sql_body, + mode=test_input.mode, + payload=compiled_payload, + source_path=test_input.test_file.relative_path, + ownership_root=test_input.test_file.ownership_root, + block_index=test_input.test_block.test_index, + explicit_name=test_input.test_block.name, + parent_name=test_input.parent_name, + case_name=test_input.case_name, + case_index=test_input.case_index, + case_fingerprint=case_fingerprint, + parameter_schema=test_input.parameter_schema, + parameter_values=test_input.parameter_values, + expected_model_names=expected_model_names, + assertion_names=assertion_names, + assertion_target_model_names=assertion_target_model_names, + read_helper_names=read_helper_names, + reference_target_model_names=reference_target_model_names, + target_model_names=tuple(target_model_names), + tested_resources=tested_resources, + ), + diagnostics=tuple( + _keyed_diagnostic(test_input=test_input, resource_name=resource_name, row=row) + for row in diagnostics + ), + ) + + +def _keyed_diagnostic( + *, test_input: CompileSqlTestInput, resource_name: str, row: NativeSqlTestDiagnosticRow +) -> tuple[tuple[str, ...], CompilerDiagnostic]: + line, column, end_line, end_column, message, help_text = row + path: Path = test_input.test_file.relative_path + return ( + (SQL_TEST_HELPER_REFERENCE_CODE, path.as_posix(), f"{line:09d}:{column:09d}", message), + CompilerDiagnostic( + phase=DiagnosticPhase.COMPILE, + severity=DiagnosticSeverity.ERROR, + code=SQL_TEST_HELPER_REFERENCE_CODE, + message=message, + resource_type=CompiledResourceType.SQL_TEST, + resource_name=resource_name, + location=SourceLocation( + path=path, line=line, column=column, end_line=end_line, end_column=end_column + ), + help=help_text, + ), + ) diff --git a/src/sqlbuild/compiler/sql_test_glue/_helpers/deferrals.py b/src/sqlbuild/compiler/sql_test_glue/_helpers/deferrals.py new file mode 100644 index 0000000000..bf25fb8907 --- /dev/null +++ b/src/sqlbuild/compiler/sql_test_glue/_helpers/deferrals.py @@ -0,0 +1,24 @@ +"""Debug-only record of SQL tests the native assembly hands back to Python.""" + +from __future__ import annotations + +import json +import os +from pathlib import Path + +from sqlbuild.compiler.lineage.constants import ANALYSIS_DEFERRAL_RECORD_PREFIX +from sqlbuild.compiler.sql_analysis.constants import ANALYSIS_RECORD_DIR_ENV_VAR +from sqlbuild.compiler.sql_test_glue.constants import SQL_TEST_ASSEMBLY_DEFERRAL_SITE + + +def record_sql_test_assembly_deferral(*, kind: str) -> None: + """Append one `{"kind", "site"}` line when the analysis record directory is set.""" + + directory: str | None = os.environ.get(ANALYSIS_RECORD_DIR_ENV_VAR) + if not directory: + return + target: Path = Path(directory) + target.mkdir(parents=True, exist_ok=True) + record: str = json.dumps({"kind": kind, "site": SQL_TEST_ASSEMBLY_DEFERRAL_SITE}) + with open(target / f"{ANALYSIS_DEFERRAL_RECORD_PREFIX}{os.getpid()}.jsonl", "a") as handle: + _ = handle.write(record + "\n") diff --git a/src/sqlbuild/compiler/sql_test_glue/constants.py b/src/sqlbuild/compiler/sql_test_glue/constants.py index 727ece2d99..8c14439660 100644 --- a/src/sqlbuild/compiler/sql_test_glue/constants.py +++ b/src/sqlbuild/compiler/sql_test_glue/constants.py @@ -3,3 +3,4 @@ from __future__ import annotations CURSOR_INTRINSIC_NAMES: tuple[str, ...] = ("__cursor_start", "__cursor_end") +SQL_TEST_ASSEMBLY_DEFERRAL_SITE: str = "sql_test_assembly" diff --git a/src/sqlbuild/compiler/sql_test_glue/main/_assemble_native_sql_tests.py b/src/sqlbuild/compiler/sql_test_glue/main/_assemble_native_sql_tests.py index b732f71039..30b1e4dd08 100644 --- a/src/sqlbuild/compiler/sql_test_glue/main/_assemble_native_sql_tests.py +++ b/src/sqlbuild/compiler/sql_test_glue/main/_assemble_native_sql_tests.py @@ -2,12 +2,26 @@ from __future__ import annotations -from sqlbuild.compiler.compile.models import CompiledSqlTest, CompileProjectInputs +import sqlbuild._native as native_module +from sqlbuild.compiler.compile.models import CompileProjectInputs +from sqlbuild.compiler.sql_test_glue._helpers.assembly import native_sql_test_assemblies +from sqlbuild.compiler.sql_test_glue.models import ( + NativeSqlTestAssembly, + NativeSqlTestAssemblyRequest, +) +from sqlbuild.compiler.sql_test_glue.types import NativeSqlTestAssemblyRow def assemble_native_sql_tests( *, inputs: CompileProjectInputs -) -> tuple[CompiledSqlTest, ...] | None: - """Return one compiled test per test input, or None where Python must assemble the tests.""" +) -> tuple[NativeSqlTestAssembly | None, ...]: + """Return one assembly per test input, or None for each test Python must assemble.""" - return None + rows: list[NativeSqlTestAssemblyRow] = native_module.assemble_compiled_sql_tests( + NativeSqlTestAssemblyRequest( + model_inputs=inputs.model_inputs, + test_inputs=inputs.test_inputs, + lexical_syntax=inputs.sql_lexical_syntax.native_mapping, + ) + ) + return native_sql_test_assemblies(test_inputs=inputs.test_inputs, rows=rows) diff --git a/src/sqlbuild/compiler/sql_test_glue/models.py b/src/sqlbuild/compiler/sql_test_glue/models.py index 0883787198..69403cb491 100644 --- a/src/sqlbuild/compiler/sql_test_glue/models.py +++ b/src/sqlbuild/compiler/sql_test_glue/models.py @@ -1,10 +1,16 @@ -"""Requests the native SQL-test planning glue reads from compiled objects.""" +"""Requests and results of the native SQL-test glue, read from compiled objects.""" from __future__ import annotations from dataclasses import dataclass -from sqlbuild.compiler.compile.models import CompiledModel, CompiledSqlTest +from sqlbuild.compiler.compile.models import ( + CompiledModel, + CompiledSqlTest, + CompileModelInput, + CompilerDiagnostic, + CompileSqlTestInput, +) @dataclass(frozen=True) @@ -32,3 +38,20 @@ class NativeSqlTestChainRequest: models: tuple[CompiledModel, ...] tests: tuple[CompiledSqlTest, ...] lexical_syntax: dict[str, object] + + +@dataclass(frozen=True) +class NativeSqlTestAssemblyRequest: + """The project's model inputs and the SQL test inputs whose compiled facts to assemble.""" + + model_inputs: tuple[CompileModelInput, ...] + test_inputs: tuple[CompileSqlTestInput, ...] + lexical_syntax: dict[str, object] + + +@dataclass(frozen=True) +class NativeSqlTestAssembly: + """One natively assembled test and the keyed diagnostics to report before it.""" + + test: CompiledSqlTest + diagnostics: tuple[tuple[tuple[str, ...], CompilerDiagnostic], ...] diff --git a/src/sqlbuild/compiler/sql_test_glue/types.py b/src/sqlbuild/compiler/sql_test_glue/types.py index 9a3fdf65c4..3e995450c1 100644 --- a/src/sqlbuild/compiler/sql_test_glue/types.py +++ b/src/sqlbuild/compiler/sql_test_glue/types.py @@ -1,4 +1,4 @@ -"""Row shapes the native SQL-test planning glue returns.""" +"""Row shapes the native SQL-test glue returns.""" from __future__ import annotations @@ -22,3 +22,13 @@ list[NativePlanWarningRow], list[str], ] +type NativeSqlTestDiagnosticRow = tuple[int, int, int, int, str, str] +type NativeSqlTestFactsRow = tuple[ + str, + list[tuple[str, str]], + list[str], + str | None, + str, + list[NativeSqlTestDiagnosticRow], +] +type NativeSqlTestAssemblyRow = tuple[NativeSqlTestFactsRow | None, str | None] diff --git a/src/sqlbuild/rule_engine/_helpers/engine/custom_rules.py b/src/sqlbuild/rule_engine/_helpers/engine/custom_rules.py index b806fb398c..ccd1fe39d2 100644 --- a/src/sqlbuild/rule_engine/_helpers/engine/custom_rules.py +++ b/src/sqlbuild/rule_engine/_helpers/engine/custom_rules.py @@ -80,6 +80,7 @@ def evaluate_custom_rules_cached( """Reuse results whose recorded fact reads are unchanged and evaluate only the rest.""" started: float = time.monotonic() + started_cpu: float = _cpu_seconds() custom: tuple[Rule, ...] = tuple(sorted(rules, key=lambda rule: rule.code)) if not custom: return CustomRulesOutcome(findings=(), cache_hits=0, cache_misses=0, custom_ms=0) @@ -105,6 +106,7 @@ def evaluate_custom_rules_cached( cache_hits=0, cache_misses=len(custom), custom_ms=_elapsed_ms(started), + custom_cpu_ms=_cpu_ms(started_cpu), ) digests: FactDigests = FactDigests( views=_views_factory(project=facts_project, project_dir=project_dir, dialect=dialect) @@ -185,6 +187,7 @@ def evaluate_custom_rules_cached( cache_hits=hits, cache_misses=misses, custom_ms=_elapsed_ms(started), + custom_cpu_ms=_cpu_ms(started_cpu), ) @@ -476,5 +479,16 @@ def _digest(value: object) -> str: return hashlib.sha256(orjson.dumps(value, default=str)).hexdigest() +def _cpu_seconds() -> float: + """This thread's CPU plus that of finished child processes, which run the rule hosts.""" + + times: os.times_result = os.times() + return time.thread_time() + times.children_user + times.children_system + + +def _cpu_ms(started: float) -> int: + return int((_cpu_seconds() - started) * 1000) + + def _elapsed_ms(started: float) -> int: return round((time.monotonic() - started) * 1000) diff --git a/src/sqlbuild/rule_engine/_helpers/engine/native.py b/src/sqlbuild/rule_engine/_helpers/engine/native.py index d9cd1a569b..a28072f54c 100644 --- a/src/sqlbuild/rule_engine/_helpers/engine/native.py +++ b/src/sqlbuild/rule_engine/_helpers/engine/native.py @@ -161,6 +161,7 @@ def evaluate_native( cache_misses=(0 if reused else native_misses) + custom.cache_misses, built_in_ms=0 if reused else int(payload.get("built_in_ms", 0)), custom_ms=custom.custom_ms, + custom_cpu_ms=custom.custom_cpu_ms, ) diff --git a/src/sqlbuild/rule_engine/_helpers/run/rules.py b/src/sqlbuild/rule_engine/_helpers/run/rules.py index 9f5b2c8c32..6b4ccd8567 100644 --- a/src/sqlbuild/rule_engine/_helpers/run/rules.py +++ b/src/sqlbuild/rule_engine/_helpers/run/rules.py @@ -231,6 +231,7 @@ def evaluate_rules( unevaluated_resources=len({item.path for item in findings if item.unevaluated}), built_in_ms=sql_ms + result.built_in_ms, custom_ms=result.custom_ms, + custom_cpu_ms=result.custom_cpu_ms, cache_hits=result.cache_hits + sql_result.cache_hits, cache_misses=result.cache_misses + sql_result.cache_misses, skipped_type_proof_rules=skipped_type_proof_rules, diff --git a/src/sqlbuild/rule_engine/models.py b/src/sqlbuild/rule_engine/models.py index 0915f9ccfb..98831bae24 100644 --- a/src/sqlbuild/rule_engine/models.py +++ b/src/sqlbuild/rule_engine/models.py @@ -311,6 +311,7 @@ class RulesResult: cache_misses: int = 0 built_in_ms: int = 0 custom_ms: int = 0 + custom_cpu_ms: int = 0 @dataclass(frozen=True) @@ -346,6 +347,7 @@ class RulesRunResult: evaluated_models: int built_in_ms: int custom_ms: int + custom_cpu_ms: int = 0 unevaluated_resources: int = 0 cache_hits: int = 0 cache_misses: int = 0 @@ -431,6 +433,7 @@ class CustomRulesOutcome: cache_hits: int cache_misses: int custom_ms: int + custom_cpu_ms: int = 0 @dataclass(frozen=True) diff --git a/tests/e2e/scripts/compile_performance_ratio/_test_types.py b/tests/e2e/scripts/compile_performance_ratio/_test_types.py index 8f517caae3..dec1ba1132 100644 --- a/tests/e2e/scripts/compile_performance_ratio/_test_types.py +++ b/tests/e2e/scripts/compile_performance_ratio/_test_types.py @@ -23,3 +23,14 @@ class PerSideCompilePerformanceRatioTestCase: expected_fragments: tuple[str, ...] expected_base_projects: tuple[str, ...] expected_head_projects: tuple[str, ...] + + +@dataclass(frozen=True) +class EnginePhaseRatioTestCase: + description: str + max_ratio: str + phase_noise_floor_ms: str + expected_return_code: int + expected_fragments: tuple[str, ...] + gate_phase: str = "contracts_cpu_ms" + compile_args: tuple[str, ...] = () diff --git a/tests/e2e/scripts/compile_performance_ratio/test_compare_compile_performance.py b/tests/e2e/scripts/compile_performance_ratio/test_compare_compile_performance.py index fda715ddc8..827a663c6c 100644 --- a/tests/e2e/scripts/compile_performance_ratio/test_compare_compile_performance.py +++ b/tests/e2e/scripts/compile_performance_ratio/test_compare_compile_performance.py @@ -11,6 +11,7 @@ from tests.e2e.scripts.compile_performance_ratio._test_types import ( CompilePerformanceRatioTestCase, + EnginePhaseRatioTestCase, PerSideCompilePerformanceRatioTestCase, ) from tests.e2e.scripts.compile_performance_ratio.helpers import ( @@ -167,5 +168,104 @@ def test_given_base_root_when_comparing_compile_performance_then_each_side_uses_ assert logged_projects(head_log) == test_case.expected_head_projects +@pytest.mark.parametrize( + "test_case", + ( + EnginePhaseRatioTestCase( + description="native-preview contracts within a generous limit of python's", + max_ratio="1000", + phase_noise_floor_ms="1000", + expected_return_code=0, + expected_fragments=( + "Engines: base `python`, head `native-preview`.", + "Gated phases: contracts_cpu_ms.", + "| contracts_cpu_ms |", + "**Result: passed.**", + ), + ), + EnginePhaseRatioTestCase( + description="a gated phase over its allowance fails on that phase alone", + max_ratio="0", + phase_noise_floor_ms="-1", + expected_return_code=1, + expected_fragments=( + "Compile performance regression: dense 20 cold contracts_cpu_ms:", + "**Result: failed.**", + ), + ), + EnginePhaseRatioTestCase( + description="model analysis CPU over its allowance with rules off fails on it alone", + max_ratio="0", + phase_noise_floor_ms="-1", + expected_return_code=1, + expected_fragments=( + "Compile arguments: `--select=*`.", + "| model_analysis_cpu_ms |", + "Compile performance regression: dense 20 cold model_analysis_cpu_ms:", + ), + gate_phase="model_analysis_cpu_ms", + compile_args=("--compile-arg=--select=*",), + ), + EnginePhaseRatioTestCase( + description="custom rule CPU over its allowance fails on it alone", + max_ratio="0", + phase_noise_floor_ms="-1", + expected_return_code=1, + expected_fragments=( + "Gated phases: custom_rules_cpu_ms.", + "| custom_rules_cpu_ms |", + "Compile performance regression: dense 20 cold custom_rules_cpu_ms:", + ), + gate_phase="custom_rules_cpu_ms", + ), + ), + ids=lambda case: case.description, +) +def test_given_two_engines_when_gating_a_phase_then_enforces_only_that_phase( + test_case: EnginePhaseRatioTestCase, +) -> None: + environment: dict[str, str] = dict(os.environ) + _ = environment.pop("GITHUB_STEP_SUMMARY", None) + result: subprocess.CompletedProcess[str] = subprocess.run( + [ + sys.executable, + "-m", + "scripts.compare_compile_performance", + "--kind", + "dense", + "--models", + "20", + "--modes", + "cold", + "--runs", + "1", + "--base-python", + sys.executable, + "--head-python", + sys.executable, + "--base-engine", + "python", + "--head-engine", + "native-preview", + "--gate-phase", + test_case.gate_phase, + "--max-ratio", + test_case.max_ratio, + "--phase-noise-floor-ms", + test_case.phase_noise_floor_ms, + *test_case.compile_args, + ], + cwd=_REPO_ROOT, + capture_output=True, + text=True, + env=environment, + check=False, + ) + + output: str = result.stdout + result.stderr + assert result.returncode == test_case.expected_return_code, output + assert all(fragment in output for fragment in test_case.expected_fragments), output + + if __name__ == "__main__": pytest.main([__file__, "-vv"]) diff --git a/tests/e2e/scripts/compiler_differential/_test_types.py b/tests/e2e/scripts/compiler_differential/_test_types.py index e488fe198a..0369dcd081 100644 --- a/tests/e2e/scripts/compiler_differential/_test_types.py +++ b/tests/e2e/scripts/compiler_differential/_test_types.py @@ -4,6 +4,8 @@ from dataclasses import dataclass +from scripts.compiler_differential.models import FailureCase + @dataclass(frozen=True) class HarnessRunTestCase: @@ -114,3 +116,32 @@ class WheelSiteReportTestCase: expected_lines: tuple[str, ...] expected_sites: frozenset[str] expected_deferrals: frozenset[str] + + +@dataclass(frozen=True) +class NativeFallbackGateTestCase: + """A recorded allow-list, an edit or sabotage, and the verdict of the next checked run.""" + + description: str + perturbation: str + appended_entries: str + expected_exit_code: int + expected_lines: tuple[str, ...] + + +@dataclass(frozen=True) +class GoldenOutputTestCase: + """Goldens recorded for one project, an edit to them, and the check verdict.""" + + description: str + golden_edit: tuple[str, str] + expected_exit_code: int + expected_lines: tuple[str, ...] + + +@dataclass(frozen=True) +class EngineErrorCaseTestCase: + """One shared all-engine error case from the failure corpus, holding its exact error.""" + + description: str + expected_error_case: FailureCase diff --git a/tests/e2e/scripts/compiler_differential/helpers.py b/tests/e2e/scripts/compiler_differential/helpers.py index 407113d85c..0c39b1c9cc 100644 --- a/tests/e2e/scripts/compiler_differential/helpers.py +++ b/tests/e2e/scripts/compiler_differential/helpers.py @@ -99,6 +99,36 @@ def _perturbed(self, **changes): _record.write(json.dumps({"kind": "legacy_fallback", "site": "orders.sql"}) + "\\n") """ +REFERENCE_SCAN_SABOTAGE: str = """ +import sqlbuild.compiler.compile._helpers.refs.references as references + +references.extract_native_sql_references = lambda **_: None +""" + +MODEL_ANALYSIS_SABOTAGE: str = """ +import sqlbuild._native as native + +native.start_model_analysis_session = lambda *_args: None +""" + +_STAGE_DISABLE_SABOTAGE: str = """ +import sqlbuild.compiler.frontier.main.native_stage_enabled as enabled +from sqlbuild.compiler.frontier.types import NativeStage + +_original = enabled.native_stage_enabled +_disabled = {{{stages}}} +enabled.native_stage_enabled = lambda stage: stage not in _disabled and _original(stage) +""" + + +def stage_disable_sabotage(stages: tuple[str, ...]) -> str: + """A perturbation switching these native stages off, so their work runs in Python.""" + + return _STAGE_DISABLE_SABOTAGE.format( + stages=", ".join(f"NativeStage({stage!r})" for stage in stages) + ) + + _BROKEN_REF_FILES: dict[str, str] = { "sqlbuild_project.toml": ( 'name = "broken_orders"\nadapter = "duckdb"\n\n' diff --git a/tests/e2e/scripts/compiler_differential/test_engine_error_cases.py b/tests/e2e/scripts/compiler_differential/test_engine_error_cases.py new file mode 100644 index 0000000000..6cd931ccf1 --- /dev/null +++ b/tests/e2e/scripts/compiler_differential/test_engine_error_cases.py @@ -0,0 +1,61 @@ +"""Every engine reports each shared user-facing error with the same exact code, text and help. + +Ports add cases to `engine_error_cases()` in the failure corpus, not here. +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +import pytest + +from scripts.compiler_differential._helpers.corpus.emitted_codes import case_emitted_codes +from scripts.compiler_differential._helpers.corpus.failure_cases import engine_error_cases +from scripts.compiler_differential.models import DifferentialOptions, EmittedCodes +from tests.e2e.scripts.compiler_differential._test_types import EngineErrorCaseTestCase + +_ENGINES: tuple[str, ...] = ("python", "native", "native-preview") + + +@pytest.mark.parametrize( + "test_case", + [ + EngineErrorCaseTestCase(description=case.name, expected_error_case=case) + for case in engine_error_cases() + ], + ids=lambda case: case.description, +) +def test_given_shared_error_case_when_compiling_on_every_engine_then_error_text_is_exact( + test_case: EngineErrorCaseTestCase, tmp_path: Path +) -> None: + emitted: dict[str, EmittedCodes] = { + engine: case_emitted_codes( + case=test_case.expected_error_case, + options=DifferentialOptions( + engines=(engine, engine), + work_dir=tmp_path / engine, + jobs=1, + stage_captures=False, + python=Path(sys.executable), + engine_environment={}, + ), + ) + for engine in _ENGINES + } + + assert { + engine: (codes.first_error, codes.first_error_message, codes.first_error_help) + for engine, codes in emitted.items() + } == { + engine: ( + test_case.expected_error_case.expected_code, + test_case.expected_error_case.expected_message, + test_case.expected_error_case.expected_help, + ) + for engine in _ENGINES + } + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/e2e/scripts/compiler_differential/test_golden_outputs.py b/tests/e2e/scripts/compiler_differential/test_golden_outputs.py new file mode 100644 index 0000000000..493038863e --- /dev/null +++ b/tests/e2e/scripts/compiler_differential/test_golden_outputs.py @@ -0,0 +1,76 @@ +"""Goldens recorded from the oracle pass an unchanged check and pinpoint any edited output.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from scripts.compiler_differential.main.differential import run_compiler_differential +from tests.e2e.scripts.compiler_differential._test_types import GoldenOutputTestCase +from tests.e2e.scripts.compiler_differential.helpers import ( + harness_arguments, + write_failure_case_project, +) + +_CASE: str = "engine-error-week-date-cursor-start" +_PROJECT: str = "orders" +_ENGINE_ARGUMENTS: tuple[str, ...] = ("--engines", "python", "native", "--expect", "failure:P001") + + +@pytest.mark.parametrize( + "test_case", + [ + GoldenOutputTestCase( + description="unchanged_goldens_pass_for_both_engines", + golden_edit=("", ""), + expected_exit_code=0, + expected_lines=("Compiler differential passed: 1 projects identical",), + ), + GoldenOutputTestCase( + description="edited_error_text_fails_for_both_engines", + golden_edit=("hour must be in 0..23", "hour must be in 1..24"), + expected_exit_code=1, + expected_lines=( + " - golden (python) at /commands/0/diagnostics/0/message", + " - golden (native) at /commands/0/diagnostics/0/message", + "Compiler differential FAILED: 1 of 1 projects differ", + ), + ), + ], + ids=lambda case: case.description, +) +def test_given_recorded_goldens_when_checking_then_only_edited_outputs_differ( + test_case: GoldenOutputTestCase, tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + project: Path = write_failure_case_project(tmp_path / _PROJECT, name=_CASE) + golden_dir: Path = tmp_path / "goldens" + recorded: int = run_compiler_differential( + harness_arguments( + work_dir=tmp_path / "record", + project=project, + extra=(*_ENGINE_ARGUMENTS, "--goldens", "update", "--golden-dir", str(golden_dir)), + ) + ) + golden: Path = golden_dir / "project" / f"{_PROJECT}.json" + _ = golden.write_text( + golden.read_text(encoding="utf-8").replace(*test_case.golden_edit), encoding="utf-8" + ) + _ = capsys.readouterr() + + exit_code: int = run_compiler_differential( + harness_arguments( + work_dir=tmp_path / "check", + project=project, + extra=(*_ENGINE_ARGUMENTS, "--goldens", "check", "--golden-dir", str(golden_dir)), + ) + ) + + output: str = capsys.readouterr().out + assert recorded == 0 + assert exit_code == test_case.expected_exit_code, output + assert all(line in output for line in test_case.expected_lines), output + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/e2e/scripts/compiler_differential/test_native_fallback_gate.py b/tests/e2e/scripts/compiler_differential/test_native_fallback_gate.py new file mode 100644 index 0000000000..45e8ceccec --- /dev/null +++ b/tests/e2e/scripts/compiler_differential/test_native_fallback_gate.py @@ -0,0 +1,193 @@ +"""The fallback allow-list gate fails on sabotaged native stages and on stale entries.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from scripts.compiler_differential.main.differential import run_compiler_differential +from tests.e2e.scripts.compiler_differential._test_types import NativeFallbackGateTestCase +from tests.e2e.scripts.compiler_differential.helpers import ( + MODEL_ANALYSIS_SABOTAGE, + REFERENCE_SCAN_SABOTAGE, + harness_arguments, + stage_disable_sabotage, + write_native_perturbation, +) + +_WAFFLE_SHOP_NATIVE_STAGES: tuple[str, ...] = ( + "attachments", + "contracts", + "declaration_files", + "declaration_scopes", + "lineage_facts", + "macro_call_store", + "macro_calls", + "model_analysis", + "model_config", + "model_loop", + "reference_extraction", + "semantic_checks", +) +_ANSWER_VANISHED: str = "native no longer answers here, so this work now runs in Python" +_FALLBACK_WITHOUT_ANSWERS: str = ( + "fallback disappeared but native answers did not appear; the stage may be switched off" +) +_VANISHED_ENTRY: str = ( + '\n[[entry]]\nengine = "native-preview"\nstage = "reference_extraction"\n' + 'site = "reference_extraction.scan"\nkind = "deferred"\ncounts = { project = 1 }\n' +) + + +@pytest.mark.parametrize( + "test_case", + [ + NativeFallbackGateTestCase( + description="recorded_list_passes", + perturbation="", + appended_entries="", + expected_exit_code=0, + expected_lines=("Compiler differential passed: 1 projects identical",), + ), + NativeFallbackGateTestCase( + description="entry_that_no_longer_occurs_without_new_native_answers_fails", + perturbation="", + appended_entries=_VANISHED_ENTRY, + expected_exit_code=1, + expected_lines=( + "Native fallback allow-list: native-preview reference_extraction " + f"reference_extraction.scan deferred (project): {_FALLBACK_WITHOUT_ANSWERS}", + ), + ), + NativeFallbackGateTestCase( + description="shipped_reference_scan_sabotaged_to_python_fails", + perturbation=REFERENCE_SCAN_SABOTAGE, + appended_entries="", + expected_exit_code=1, + expected_lines=( + "Native fallback allow-list: native-preview reference_extraction " + "reference_extraction.scan deferred (project): ", + "not on the allow-list; port it or list it with a reason", + ), + ), + NativeFallbackGateTestCase( + description="preview_model_analysis_sabotaged_to_python_fails", + perturbation=MODEL_ANALYSIS_SABOTAGE, + appended_entries="", + expected_exit_code=1, + expected_lines=( + "Native fallback allow-list: native-preview model_analysis analysis_session " + "session (project): ", + "Compiler differential FAILED: 0 of 1 projects differ", + ), + ), + NativeFallbackGateTestCase( + description="shipped_stages_switched_to_python_fail", + perturbation=stage_disable_sabotage(("reference_extraction", "declaration_files")), + appended_entries="", + expected_exit_code=1, + expected_lines=( + "Native fallback allow-list: native-preview reference_extraction " + f"reference_extraction.native reference_scans (project): {_ANSWER_VANISHED}", + "Native fallback allow-list: native-preview declaration_files " + f"declaration_files.native parsed_files (project): {_ANSWER_VANISHED}", + "Intended? Run `make compiler-baselines`", + ), + ), + NativeFallbackGateTestCase( + description="every_native_stage_switched_to_python_fails_by_name", + perturbation=stage_disable_sabotage(_WAFFLE_SHOP_NATIVE_STAGES), + appended_entries="", + expected_exit_code=1, + expected_lines=tuple( + f"Native fallback allow-list: native-preview {stage} {stage}.native " + for stage in _WAFFLE_SHOP_NATIVE_STAGES + ), + ), + ], + ids=lambda case: case.description, +) +def test_given_recorded_allow_list_when_native_defers_more_or_less_then_the_gate_fails( + test_case: NativeFallbackGateTestCase, tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + allow_list: Path = tmp_path / "native_fallbacks.toml" + recorded: int = run_compiler_differential( + harness_arguments( + work_dir=tmp_path / "record", + extra=("--native-fallbacks", "update", "--native-fallback-list", str(allow_list)), + ) + ) + _ = allow_list.write_text( + allow_list.read_text(encoding="utf-8") + test_case.appended_entries, encoding="utf-8" + ) + sabotage: Path = write_native_perturbation(tmp_path / "sabotage", source=test_case.perturbation) + _ = capsys.readouterr() + + exit_code: int = run_compiler_differential( + harness_arguments( + work_dir=tmp_path / "check", + extra=( + "--native-fallbacks", + "check", + "--native-fallback-list", + str(allow_list), + "--engine-env", + f"native-preview:PYTHONPATH={sabotage}", + ), + ) + ) + + output: str = capsys.readouterr().out + assert recorded == 0 + assert exit_code == test_case.expected_exit_code, output + assert all(line in output for line in test_case.expected_lines), output + + +@pytest.mark.parametrize( + "test_case", + [ + NativeFallbackGateTestCase( + description="sql_test_glue_switched_off_is_not_a_finished_port", + perturbation=stage_disable_sabotage(("sql_test_glue",)), + appended_entries="", + expected_exit_code=1, + expected_lines=( + "Native fallback allow-list: native-preview sql_test_glue sql_test_glue.native " + f"sql_test_assemblies (fixture): {_ANSWER_VANISHED}", + "Native fallback allow-list: native-preview sql_test_glue sql_test_glue.native " + f"sql_test_plans (fixture): {_ANSWER_VANISHED}", + "Native fallback allow-list: 2 problems", + ), + ), + ], + ids=lambda case: case.description, +) +def test_given_committed_allow_list_when_fallback_only_stage_is_switched_off_then_gate_refuses( + test_case: NativeFallbackGateTestCase, tmp_path: Path, capsys: pytest.CaptureFixture[str] +) -> None: + sabotage: Path = write_native_perturbation(tmp_path / "sabotage", source=test_case.perturbation) + _ = capsys.readouterr() + + exit_code: int = run_compiler_differential( + [ + "--corpus", + "fixtures", + "--jobs", + "2", + "--work-dir", + str(tmp_path / "check"), + "--native-fallbacks", + "check", + "--engine-env", + f"native-preview:PYTHONPATH={sabotage}", + ] + ) + + output: str = capsys.readouterr().out + assert exit_code == test_case.expected_exit_code, output + assert all(line in output for line in test_case.expected_lines), output + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/e2e/src/sqlbuild/cli/commands/main/build/test_compile_json_behavior.py b/tests/e2e/src/sqlbuild/cli/commands/main/build/test_compile_json_behavior.py index 1bf00f83ce..cbdbaa803f 100644 --- a/tests/e2e/src/sqlbuild/cli/commands/main/build/test_compile_json_behavior.py +++ b/tests/e2e/src/sqlbuild/cli/commands/main/build/test_compile_json_behavior.py @@ -66,12 +66,15 @@ def test_given_waffle_shop_when_running_compile_json_then_it_reports_offline_que "graph_ms", "lineage_ms", "contracts_ms", + "contracts_cpu_ms", "write_ms", "attachment_ms", "built_in_rules_ms", "custom_rules_ms", + "custom_rules_cpu_ms", "early_lint_wait_ms", "model_analysis_ms", + "model_analysis_cpu_ms", "analysis_preparation_ms", "analysis_native_ms", "analysis_projection_ms", diff --git a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_dense_compile_performance.py b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_dense_compile_performance.py index 606879ed41..dec0bf7ea8 100644 --- a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_dense_compile_performance.py +++ b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_dense_compile_performance.py @@ -125,6 +125,7 @@ def test_given_dense_project_when_compiling_cold_then_preserves_rules_semantics_ assert timings["rule_cache_misses"] == 2 * test_case.model_count + 1 assert timings["built_in_rules_ms"] > 0 assert timings["custom_rules_ms"] > 0 + assert timings["custom_rules_cpu_ms"] > 0 assert result.semantic_fingerprint == test_case.expected_fingerprint assert result.elapsed_seconds < test_case.expected_max_wall_seconds assert result.peak_rss_bytes < test_case.expected_max_rss_bytes diff --git a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_fresh_process_compile_cache_performance.py b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_fresh_process_compile_cache_performance.py index 34566e6567..2b3a388cf0 100644 --- a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_fresh_process_compile_cache_performance.py +++ b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_fresh_process_compile_cache_performance.py @@ -29,7 +29,7 @@ _MAX_EDIT_TO_COLD_RATIO: float = 0.70 # Writing the cache during a cold compile must stay a small same-runner cost over --no-cache. _MAX_CACHE_WRITE_CPU_OVERHEAD_RATIO: float = 1.10 -_MAX_CACHE_WRITE_WALL_OVERHEAD_RATIO: float = 1.15 +_MAX_CACHE_WRITE_WALL_OVERHEAD_RATIO: float = 1.20 _MAX_LARGE_CACHE_WRITE_CPU_OVERHEAD_RATIO: float = 1.15 diff --git a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_native_analysis_seams.py b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_native_analysis_seams.py index bd27e5c2d5..89d06a242c 100644 --- a/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_native_analysis_seams.py +++ b/tests/e2e/src/sqlbuild/cli/commands/main/compile/test_native_analysis_seams.py @@ -8,11 +8,13 @@ import pytest import sqlbuild._native as native_module +from sqlbuild.compiler.analysis_session.models import NativeModelAnalyses from sqlbuild.compiler.compile.models import CompiledProject from sqlbuild.compiler.contracts.models import ContractValidationResult from sqlbuild.compiler.lineage.models import ProjectColumnLineage from sqlbuild.compiler.planner.models import NativeSqlTestArtifact from sqlbuild.compiler.project_assembly.models import NativeProjectResources +from sqlbuild.compiler.sql_test_glue.models import NativeSqlTestAssembly from tests.e2e.src.sqlbuild.cli.commands.main.compile._test_types import ( NativeAnalysisSeamTestCase, ) @@ -36,7 +38,7 @@ "assemble_native_project_resources": [ANY], "infer_native_expression_source_shapes": [ANY], "analyze_native_model_sql": [ANY], - "assemble_native_sql_tests": [None], + "assemble_native_sql_tests": [ANY], "complete_native_semantic_diagnostics": [ANY], "evaluate_native_model_contracts": [ANY], "native_promotion_conflict_diagnostics": [()], @@ -81,8 +83,13 @@ def test_given_project_when_compiling_with_each_engine_then_native_seams_answer_ ) assert isinstance(preview_seams["build_native_column_lineage"][0], ProjectColumnLineage) assert isinstance(preview_seams["assemble_native_project_resources"][0], NativeProjectResources) - assert isinstance(preview_seams["analyze_native_model_sql"][0], dict) + assert isinstance(preview_seams["analyze_native_model_sql"][0], NativeModelAnalyses) + assert preview_seams["analyze_native_model_sql"][0].session is not None assert isinstance(preview_seams["infer_native_expression_source_shapes"][0], tuple) + assembled_tests: object = preview_seams["assemble_native_sql_tests"][0] + assert isinstance(assembled_tests, tuple) + assert assembled_tests + assert all(isinstance(assembled, NativeSqlTestAssembly) for assembled in assembled_tests) planned_artifacts: object = preview_seams["plan_native_sql_test_artifacts"][0] assert isinstance(planned_artifacts, tuple) assert planned_artifacts diff --git a/tests/goldens/compiler/example/hero-shop.json b/tests/goldens/compiler/example/hero-shop.json new file mode 100644 index 0000000000..e9235feb79 --- /dev/null +++ b/tests/goldens/compiler/example/hero-shop.json @@ -0,0 +1,220 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "models/finance/daily_revenue.sql": [ + "SELECT", + " CAST(paid_at AS DATE) AS revenue_date,", + " SUM(amount_cents) AS total_revenue_cents", + "FROM __seed(\"payments\")", + "GROUP BY", + " CAST(paid_at AS DATE)", + "" + ] + }, + "manifest": { + "nodes": { + "model.waffle_shop.daily_revenue": { + "database": null, + "schema": "prod", + "name": "daily_revenue", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/finance/daily_revenue.sql", + "original_file_path": "models/finance/daily_revenue.sql", + "unique_id": "model.waffle_shop.daily_revenue", + "fqn": [ + "waffle_shop", + "models", + "finance", + "daily_revenue" + ], + "alias": "daily_revenue", + "config": { + "enabled": true, + "alias": null, + "schema": "prod", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Daily revenue from successful payments", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "prod.daily_revenue", + "depends_on": { + "macros": [], + "nodes": [ + "seed.waffle_shop.payments" + ] + } + }, + "seed.waffle_shop.payments": { + "database": null, + "schema": "prod", + "name": "payments", + "resource_type": "seed", + "package_name": "waffle_shop", + "path": "seeds/payments.csv", + "original_file_path": "seeds/payments.csv", + "unique_id": "seed.waffle_shop.payments", + "fqn": [ + "waffle_shop", + "seeds", + "payments" + ], + "alias": "payments", + "config": { + "enabled": true, + "alias": null, + "schema": "prod", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Successful payments.", + "columns": { + "payment_id": { + "name": "payment_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "paid_at": { + "name": "paid_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount_cents": { + "name": "amount_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "prod.payments", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": {}, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.waffle_shop.daily_revenue": [ + "seed.waffle_shop.payments" + ], + "seed.waffle_shop.payments": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/example/tidy-shop.json b/tests/goldens/compiler/example/tidy-shop.json new file mode 100644 index 0000000000..c7db14dd9c --- /dev/null +++ b/tests/goldens/compiler/example/tidy-shop.json @@ -0,0 +1,115 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "models/daily_revenue.sql": [ + "SELECT CAST('2026-04-01' AS DATE) AS revenue_date, 2850 AS total_revenue_cents", + "" + ] + }, + "manifest": { + "nodes": { + "model.waffle_shop.daily_revenue": { + "database": null, + "schema": "prod", + "name": "daily_revenue", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/daily_revenue.sql", + "original_file_path": "models/daily_revenue.sql", + "unique_id": "model.waffle_shop.daily_revenue", + "fqn": [ + "waffle_shop", + "models", + "daily_revenue" + ], + "alias": "daily_revenue", + "config": { + "enabled": true, + "alias": null, + "schema": "prod", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Daily revenue from successful payments", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "prod.daily_revenue", + "depends_on": { + "macros": [], + "nodes": [] + } + } + }, + "sources": {}, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.waffle_shop.daily_revenue": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/example/waffle-shop.json b/tests/goldens/compiler/example/waffle-shop.json new file mode 100644 index 0000000000..e18976bf03 --- /dev/null +++ b/tests/goldens/compiler/example/waffle-shop.json @@ -0,0 +1,2136 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/customer_status_snapshot/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"customer_status_snapshot\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/customer_status_snapshot/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"customer_status_snapshot\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/daily_order_partitioned/not_null__order_date.sql": [ + "SELECT order_date", + "FROM __ref(\"daily_order_partitioned\")", + "WHERE order_date IS NULL", + "" + ], + "audits/generic/daily_order_partitioned/waffles_ordered_is_positive.sql": [ + "SELECT *", + "FROM __ref(\"daily_order_partitioned\")", + "WHERE NOT (waffles_ordered > 0)", + "" + ], + "audits/generic/daily_order_rollup/daily_orders_placed_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"daily_order_rollup\")", + "WHERE NOT (orders_placed >= 0)", + "" + ], + "audits/generic/daily_order_rollup/not_null__activity_day.sql": [ + "SELECT activity_day", + "FROM __ref(\"daily_order_rollup\")", + "WHERE activity_day IS NULL", + "" + ], + "audits/generic/daily_revenue/revenue_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"daily_revenue\")", + "WHERE NOT (total_revenue_cents >= 0)", + "" + ], + "audits/generic/dim_customers/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"dim_customers\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/dim_customers/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"dim_customers\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/fact_orders/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"fact_orders\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/hourly_activity_with_daily_context/day_orders_cover_hourly_orders.sql": [ + "SELECT *", + "FROM __ref(\"hourly_activity_with_daily_context\")", + "WHERE NOT (day_orders_placed >= orders_placed)", + "" + ], + "audits/generic/hourly_activity_with_daily_context/not_null__activity_hour.sql": [ + "SELECT activity_hour", + "FROM __ref(\"hourly_activity_with_daily_context\")", + "WHERE activity_hour IS NULL", + "" + ], + "audits/generic/hourly_order_activity/not_null__activity_hour.sql": [ + "SELECT activity_hour", + "FROM __ref(\"hourly_order_activity\")", + "WHERE activity_hour IS NULL", + "" + ], + "audits/generic/hourly_order_activity/orders_placed_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"hourly_order_activity\")", + "WHERE NOT (orders_placed >= 0)", + "" + ], + "audits/generic/order_status_index/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"order_status_index\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/order_status_index/unique__order_id.sql": [ + "SELECT order_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"order_status_index\")", + "WHERE order_id IS NOT NULL", + "GROUP BY order_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_customers/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_customers\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/stg_customers/not_null__email.sql": [ + "SELECT email", + "FROM __ref(\"stg_customers\")", + "WHERE email IS NULL", + "" + ], + "audits/generic/stg_customers/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_customers\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_orders/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"stg_orders\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'preparing', 'ready', 'completed', 'cancelled')", + "" + ], + "audits/generic/stg_orders/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_orders\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/stg_orders/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_orders\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/stg_orders/relationships__waffle_type_id.sql": [ + "SELECT waffle_type_id", + "FROM __ref(\"stg_orders\")", + "WHERE waffle_type_id IS NOT NULL", + " AND waffle_type_id NOT IN (", + " SELECT waffle_type_id", + " FROM __seed(\"waffle_types\")", + " WHERE waffle_type_id IS NOT NULL", + " )", + "" + ], + "audits/generic/stg_orders/unique__order_id.sql": [ + "SELECT order_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_orders\")", + "WHERE order_id IS NOT NULL", + "GROUP BY order_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_payments/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_payments\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/stg_payments/not_null__payment_id.sql": [ + "SELECT payment_id", + "FROM __ref(\"stg_payments\")", + "WHERE payment_id IS NULL", + "" + ], + "audits/generic/stg_payments/relationships__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_payments\")", + "WHERE order_id IS NOT NULL", + " AND order_id NOT IN (", + " SELECT id", + " FROM __source(\"raw__orders\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/stg_payments/unique__payment_id.sql": [ + "SELECT payment_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_payments\")", + "WHERE payment_id IS NOT NULL", + "GROUP BY payment_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/waffle_types/not_null__waffle_type_id.sql": [ + "SELECT waffle_type_id", + "FROM __seed(\"waffle_types\")", + "WHERE waffle_type_id IS NULL", + "" + ], + "audits/generic/waffle_types/unique__waffle_type_id.sql": [ + "SELECT waffle_type_id, COUNT(*) AS duplicate_count", + "FROM __seed(\"waffle_types\")", + "WHERE waffle_type_id IS NOT NULL", + "GROUP BY waffle_type_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/singular/fact_orders_have_customers.sql": [ + "SELECT f.order_id, f.customer_id", + "FROM __ref(\"fact_orders\") f", + "LEFT JOIN __ref(\"dim_customers\") d ON f.customer_id = d.customer_id", + "WHERE d.customer_id IS NULL", + "" + ], + "functions/sql/table_fn__customer_orders.sql": [ + "CREATE OR REPLACE MACRO dev.table_fn__customer_orders(p_customer_id) AS TABLE", + "SELECT", + " order_id,", + " ordered_at,", + " waffle_name,", + " line_total_cents,", + " order_status,", + " is_completed_order", + "FROM __ref(\"fact_orders\")", + "WHERE customer_id = p_customer_id", + "" + ], + "functions/sql/udf__is_completed_order.sql": [ + "CREATE OR REPLACE MACRO dev.udf__is_completed_order(order_status) AS (", + "order_status = 'completed'", + ")", + "" + ], + "models/intermediate/customer_status_snapshot.sql": [ + "SELECT", + " customer_id,", + " MAX(ordered_at) AS last_ordered_at,", + " MAX(order_status) AS latest_order_status,", + " COUNT(*) AS total_orders,", + " SUM(line_total_cents) AS total_revenue_cents", + "FROM __ref(\"fact_orders\")", + "GROUP BY customer_id", + "" + ], + "models/intermediate/order_status_index.sql": [ + "SELECT", + " order_id,", + " customer_id,", + " order_status,", + " ordered_at,", + " line_total_cents", + "FROM __ref(\"fact_orders\")", + "" + ], + "models/marts/daily_order_partitioned.sql": [ + "SELECT", + " CAST(o.ordered_at AS DATE) AS order_date,", + " COUNT(DISTINCT o.order_id) AS order_count,", + " SUM(o.quantity) AS waffles_ordered,", + " COUNT(DISTINCT o.customer_id) AS unique_customers", + "FROM __ref(\"stg_orders\") o", + "WHERE CAST(o.ordered_at AS DATE) >= CAST(@@@partition_start AS DATE)", + " AND CAST(o.ordered_at AS DATE) < CAST(@@@partition_end AS DATE)", + "GROUP BY CAST(o.ordered_at AS DATE)", + "" + ], + "models/marts/daily_order_rollup.sql": [ + "SELECT", + " DATE_TRUNC('day', activity_hour) AS activity_day,", + " SUM(orders_placed) AS orders_placed,", + " SUM(waffles_ordered) AS waffles_ordered,", + " SUM(revenue_cents) AS revenue_cents", + "FROM __ref(\"hourly_order_activity\")", + "GROUP BY DATE_TRUNC('day', activity_hour)", + "" + ], + "models/marts/daily_revenue.sql": [ + "SELECT", + " CAST(o.ordered_at AS DATE) AS revenue_date,", + " COUNT(DISTINCT o.order_id) AS order_count,", + " SUM(o.quantity) AS waffles_sold,", + " SUM(p.amount_cents) AS total_revenue_cents,", + " ROUND((SUM(p.amount_cents)) / 100.0, 2) AS total_revenue_dollars,", + " SUM(p.amount_cents) / COUNT(DISTINCT o.order_id) AS avg_order_value_cents", + "FROM __ref(\"stg_orders\") o", + "INNER JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id AND p.payment_status = 'success'", + "GROUP BY CAST(o.ordered_at AS DATE)", + "" + ], + "models/marts/dim_customers.sql": [ + "SELECT", + " c.customer_id,", + " c.first_name,", + " c.last_name,", + " c.email,", + " c.created_at AS customer_since,", + " COUNT(DISTINCT o.order_id) AS lifetime_orders,", + " COALESCE(SUM(p.amount_cents), 0) AS lifetime_spend_cents", + "FROM __ref(\"stg_customers\") c", + "LEFT JOIN __ref(\"stg_orders\") o ON c.customer_id = o.customer_id", + "LEFT JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id AND p.payment_status = 'success'", + "GROUP BY c.customer_id, c.first_name, c.last_name, c.email, c.created_at", + "" + ], + "models/marts/fact_orders.sql": [ + "SELECT", + " o.order_id,", + " o.customer_id,", + " o.waffle_type_id,", + " w.waffle_name,", + " w.category AS waffle_category,", + " o.quantity,", + " w.price_cents * o.quantity AS line_total_cents,", + " o.ordered_at,", + " o.status AS order_status,", + " __udf(\"udf__is_completed_order\")(o.status) AS is_completed_order,", + " p.payment_method,", + " p.payment_status,", + " p.amount_cents AS payment_amount_cents", + "FROM __ref(\"stg_orders\") o", + "LEFT JOIN __seed(\"waffle_types\") w ON o.waffle_type_id = w.waffle_type_id", + "LEFT JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id", + "" + ], + "models/marts/hourly_activity_with_daily_context.sql": [ + "SELECT", + " h.activity_hour,", + " h.orders_placed,", + " d.orders_placed AS day_orders_placed,", + " h.waffles_ordered,", + " h.revenue_cents", + "FROM __ref(\"hourly_order_activity\") h", + "INNER JOIN __ref(\"daily_order_rollup\") d", + " ON DATE_TRUNC('day', h.activity_hour) = d.activity_day", + "" + ], + "models/marts/hourly_order_activity.sql": [ + "SELECT", + " DATE_TRUNC('hour', o.ordered_at) AS activity_hour,", + " COUNT(*) AS orders_placed,", + " SUM(o.quantity) AS waffles_ordered,", + " SUM(o.line_total_cents) AS revenue_cents", + "FROM __ref(\"fact_orders\") o", + "GROUP BY DATE_TRUNC('hour', o.ordered_at)", + "" + ], + "models/staging/stg_customers.sql": [ + "SELECT", + " id AS customer_id,", + " first_name,", + " last_name,", + " email,", + " created_at", + "FROM __source(\"raw__customers\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT", + " id AS order_id,", + " customer_id,", + " waffle_type_id,", + " quantity,", + " ordered_at,", + " status", + "FROM __source(\"raw__orders\")", + "" + ], + "models/staging/stg_payments.sql": [ + "SELECT", + " id AS payment_id,", + " order_id,", + " amount_cents,", + " payment_method,", + " paid_at,", + " status AS payment_status", + "FROM __source(\"raw__payments\")", + "" + ], + "tests/_chain_/daily_revenue__stg_orders__stg_payments/test_daily_revenue_chain.sql": [ + "WITH __source__raw__orders AS (SELECT", + " 1 AS id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status", + " UNION ALL", + " SELECT", + " 2 AS id,", + " 101 AS customer_id,", + " 1 AS waffle_type_id,", + " 1 AS quantity,", + " CAST('2026-04-01 11:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__ref__stg_orders AS (SELECT", + " id AS order_id,", + " customer_id,", + " waffle_type_id,", + " quantity,", + " ordered_at,", + " status", + "FROM __source__raw__orders),", + "__source__raw__payments AS (SELECT", + " 10 AS id,", + " 1 AS order_id,", + " 2850 AS amount_cents,", + " 'card' AS payment_method,", + " CAST('2026-04-01 10:05:00' AS TIMESTAMP) AS paid_at,", + " 'success' AS status", + " UNION ALL", + " SELECT", + " 11 AS id,", + " 2 AS order_id,", + " 850 AS amount_cents,", + " 'cash' AS payment_method,", + " CAST('2026-04-01 11:10:00' AS TIMESTAMP) AS paid_at,", + " 'failed' AS status),", + "__ref__stg_payments AS (SELECT", + " id AS payment_id,", + " order_id,", + " amount_cents,", + " payment_method,", + " paid_at,", + " status AS payment_status", + "FROM __source__raw__payments),", + "__ref__daily_revenue AS (SELECT", + " CAST(o.ordered_at AS DATE) AS revenue_date,", + " COUNT(DISTINCT o.order_id) AS order_count,", + " SUM(o.quantity) AS waffles_sold,", + " SUM(p.amount_cents) AS total_revenue_cents,", + " ROUND((SUM(p.amount_cents)) / 100.0, 2) AS total_revenue_dollars,", + " SUM(p.amount_cents) / COUNT(DISTINCT o.order_id) AS avg_order_value_cents", + "FROM __ref__stg_orders o", + "INNER JOIN __ref__stg_payments p ON o.order_id = p.order_id AND p.payment_status = 'success'", + "GROUP BY CAST(o.ordered_at AS DATE)),", + "__actual__stg_orders AS (SELECT * FROM __ref__stg_orders),", + "__expected__stg_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status", + " UNION ALL", + " SELECT", + " 2 AS order_id,", + " 101 AS customer_id,", + " 1 AS waffle_type_id,", + " 1 AS quantity,", + " CAST('2026-04-01 11:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__actual__stg_payments AS (SELECT * FROM __ref__stg_payments),", + "__expected__stg_payments AS (SELECT", + " 10 AS payment_id,", + " 1 AS order_id,", + " 2850 AS amount_cents,", + " 'card' AS payment_method,", + " CAST('2026-04-01 10:05:00' AS TIMESTAMP) AS paid_at,", + " 'success' AS payment_status", + " UNION ALL", + " SELECT", + " 11 AS payment_id,", + " 2 AS order_id,", + " 850 AS amount_cents,", + " 'cash' AS payment_method,", + " CAST('2026-04-01 11:10:00' AS TIMESTAMP) AS paid_at,", + " 'failed' AS payment_status),", + "__actual__daily_revenue AS (SELECT * FROM __ref__daily_revenue),", + "__expected__daily_revenue AS (SELECT", + " CAST('2026-04-01' AS DATE) AS revenue_date,", + " 1 AS order_count,", + " 3 AS waffles_sold,", + " 2850 AS total_revenue_cents,", + " 28.5 AS total_revenue_dollars,", + " 2850 AS avg_order_value_cents),", + "__assert__daily_revenue_is_non_negative AS (SELECT *", + " FROM __ref__daily_revenue", + " WHERE total_revenue_cents < 0)", + "SELECT 0 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'stg_payments' AS model_name, (SELECT COUNT(*) FROM __actual__stg_payments) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_payments) AS expected_count, (SELECT COUNT(*) FROM (SELECT payment_id, order_id, amount_cents, payment_method, paid_at, payment_status FROM __actual__stg_payments EXCEPT SELECT payment_id, order_id, amount_cents, payment_method, paid_at, payment_status FROM __expected__stg_payments) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT payment_id, order_id, amount_cents, payment_method, paid_at, payment_status FROM __expected__stg_payments EXCEPT SELECT payment_id, order_id, amount_cents, payment_method, paid_at, payment_status FROM __actual__stg_payments) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 2 AS step_index, 'daily_revenue' AS model_name, (SELECT COUNT(*) FROM __actual__daily_revenue) AS actual_count, (SELECT COUNT(*) FROM __expected__daily_revenue) AS expected_count, (SELECT COUNT(*) FROM (SELECT revenue_date, order_count, waffles_sold, total_revenue_cents, total_revenue_dollars, avg_order_value_cents FROM __actual__daily_revenue EXCEPT SELECT revenue_date, order_count, waffles_sold, total_revenue_cents, total_revenue_dollars, avg_order_value_cents FROM __expected__daily_revenue) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT revenue_date, order_count, waffles_sold, total_revenue_cents, total_revenue_dollars, avg_order_value_cents FROM __expected__daily_revenue EXCEPT SELECT revenue_date, order_count, waffles_sold, total_revenue_cents, total_revenue_dollars, avg_order_value_cents FROM __actual__daily_revenue) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 3 AS step_index, 'assertion daily_revenue_is_non_negative' AS model_name, (SELECT COUNT(*) FROM __assert__daily_revenue_is_non_negative) AS actual_count, 0 AS expected_count, (SELECT COUNT(*) FROM __assert__daily_revenue_is_non_negative) AS unexpected_count, 0 AS missing_count", + "" + ], + "tests/fact_orders/test_fact_orders.sql": [ + "WITH __ref__stg_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__ref__stg_payments AS (SELECT", + " 10 AS payment_id,", + " 1 AS order_id,", + " 2850 AS amount_cents,", + " 'card' AS payment_method,", + " CAST('2026-04-01 10:05:00' AS TIMESTAMP) AS paid_at,", + " 'success' AS payment_status),", + "__seed__waffle_types AS (SELECT", + " 2 AS waffle_type_id,", + " 'Liege' AS waffle_name,", + " 'sweet' AS category,", + " 950 AS price_cents),", + "__ref__fact_orders AS (SELECT", + " o.order_id,", + " o.customer_id,", + " o.waffle_type_id,", + " w.waffle_name,", + " w.category AS waffle_category,", + " o.quantity,", + " w.price_cents * o.quantity AS line_total_cents,", + " o.ordered_at,", + " o.status AS order_status,", + " dev.udf__is_completed_order(o.status) AS is_completed_order,", + " p.payment_method,", + " p.payment_status,", + " p.amount_cents AS payment_amount_cents", + "FROM __ref__stg_orders o", + "LEFT JOIN __seed__waffle_types w ON o.waffle_type_id = w.waffle_type_id", + "LEFT JOIN __ref__stg_payments p ON o.order_id = p.order_id),", + "__actual__fact_orders AS (SELECT * FROM __ref__fact_orders),", + "__expected__fact_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 'Liege' AS waffle_name,", + " 'sweet' AS waffle_category,", + " 3 AS quantity,", + " 2850 AS line_total_cents,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS order_status,", + " TRUE AS is_completed_order,", + " 'card' AS payment_method,", + " 'success' AS payment_status,", + " 2850 AS payment_amount_cents),", + "__assert__line_totals_are_non_negative AS (SELECT *", + " FROM __ref__fact_orders", + " WHERE line_total_cents < 0)", + "SELECT 0 AS step_index, 'fact_orders' AS model_name, (SELECT COUNT(*) FROM __actual__fact_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__fact_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, payment_method, payment_status, payment_amount_cents FROM __actual__fact_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, payment_method, payment_status, payment_amount_cents FROM __expected__fact_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, payment_method, payment_status, payment_amount_cents FROM __expected__fact_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, payment_method, payment_status, payment_amount_cents FROM __actual__fact_orders) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'assertion line_totals_are_non_negative' AS model_name, (SELECT COUNT(*) FROM __assert__line_totals_are_non_negative) AS actual_count, 0 AS expected_count, (SELECT COUNT(*) FROM __assert__line_totals_are_non_negative) AS unexpected_count, 0 AS missing_count", + "" + ], + "tests/macro calculates_line_total_cents/calculates_line_total_cents.sql": [ + "WITH input_values AS (SELECT 950 AS price_cents, 3 AS quantity),", + "__actual__macro_calculates_line_total_cents AS (SELECT price_cents * quantity AS line_total_cents", + " FROM input_values),", + "__expected__macro_calculates_line_total_cents AS (SELECT 2850 AS line_total_cents)", + "SELECT 0 AS step_index, 'macro calculates_line_total_cents' AS model_name, (SELECT COUNT(*) FROM __actual__macro_calculates_line_total_cents) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_calculates_line_total_cents) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_calculates_line_total_cents EXCEPT SELECT * FROM __expected__macro_calculates_line_total_cents) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_calculates_line_total_cents EXCEPT SELECT * FROM __actual__macro_calculates_line_total_cents) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_orders/test_stg_orders.sql": [ + "WITH __source__raw__orders AS (SELECT", + " 1 AS id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__ref__stg_orders AS (SELECT", + " id AS order_id,", + " customer_id,", + " waffle_type_id,", + " quantity,", + " ordered_at,", + " status", + "FROM __source__raw__orders),", + "__actual__stg_orders AS (SELECT * FROM __ref__stg_orders),", + "__expected__stg_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__assert__order_ids_are_not_null AS (SELECT *", + " FROM __ref__stg_orders", + " WHERE order_id IS NULL)", + "SELECT 0 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'assertion order_ids_are_not_null' AS model_name, (SELECT COUNT(*) FROM __assert__order_ids_are_not_null) AS actual_count, 0 AS expected_count, (SELECT COUNT(*) FROM __assert__order_ids_are_not_null) AS unexpected_count, 0 AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.waffle_shop.customer_status_snapshot": { + "database": null, + "schema": "dev", + "name": "customer_status_snapshot", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/intermediate/customer_status_snapshot.sql", + "original_file_path": "models/intermediate/customer_status_snapshot.sql", + "unique_id": "model.waffle_shop.customer_status_snapshot", + "fqn": [ + "waffle_shop", + "models", + "intermediate", + "customer_status_snapshot" + ], + "alias": "customer_status_snapshot", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "intermediate", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "merge", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "customer_id" + ], + "on_schema_change": "sync_all_columns", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "intermediate", + "acceptance" + ], + "description": "Merge-based customer snapshot with timestamp cursor and explicit backfill policies.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.customer_status_snapshot", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.order_status_index": { + "database": null, + "schema": "dev", + "name": "order_status_index", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/intermediate/order_status_index.sql", + "original_file_path": "models/intermediate/order_status_index.sql", + "unique_id": "model.waffle_shop.order_status_index", + "fqn": [ + "waffle_shop", + "models", + "intermediate", + "order_status_index" + ], + "alias": "order_status_index", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "intermediate", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "order_id" + ], + "on_schema_change": "append_new_columns", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "intermediate", + "acceptance" + ], + "description": "Integer-cursor incremental projection over fact orders.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.order_status_index", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.daily_order_partitioned": { + "database": null, + "schema": "dev", + "name": "daily_order_partitioned", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_order_partitioned.sql", + "original_file_path": "models/marts/daily_order_partitioned.sql", + "unique_id": "model.waffle_shop.daily_order_partitioned", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_order_partitioned" + ], + "alias": "daily_order_partitioned", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "partition_tracked", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Partition-tracked daily order summary using custom materialization.", + "columns": { + "order_date": { + "name": "order_date", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.daily_order_partitioned", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_orders" + ] + } + }, + "model.waffle_shop.daily_order_rollup": { + "database": null, + "schema": "dev", + "name": "daily_order_rollup", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_order_rollup.sql", + "original_file_path": "models/marts/daily_order_rollup.sql", + "unique_id": "model.waffle_shop.daily_order_rollup", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_order_rollup" + ], + "alias": "daily_order_rollup", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts", + "acceptance" + ], + "description": "Downstream daily microbatch rollup with a wider batch size than its hourly upstream.", + "columns": { + "activity_day": { + "name": "activity_day", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.daily_order_rollup", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.hourly_order_activity" + ] + } + }, + "model.waffle_shop.daily_revenue": { + "database": null, + "schema": "dev", + "name": "daily_revenue", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_revenue.sql", + "original_file_path": "models/marts/daily_revenue.sql", + "unique_id": "model.waffle_shop.daily_revenue", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_revenue" + ], + "alias": "daily_revenue", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Daily revenue aggregation.", + "columns": { + "revenue_date": { + "name": "revenue_date", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.daily_revenue", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.dim_customers": { + "database": null, + "schema": "dev", + "name": "dim_customers", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/dim_customers.sql", + "original_file_path": "models/marts/dim_customers.sql", + "unique_id": "model.waffle_shop.dim_customers", + "fqn": [ + "waffle_shop", + "models", + "marts", + "dim_customers" + ], + "alias": "dim_customers", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "customer_id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Customer dimension with lifetime metrics.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.dim_customers", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_customers", + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.fact_orders": { + "database": null, + "schema": "dev", + "name": "fact_orders", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/fact_orders.sql", + "original_file_path": "models/marts/fact_orders.sql", + "unique_id": "model.waffle_shop.fact_orders", + "fqn": [ + "waffle_shop", + "models", + "marts", + "fact_orders" + ], + "alias": "fact_orders", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Order fact table with waffle and payment details.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.fact_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.udf__is_completed_order", + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.hourly_activity_with_daily_context": { + "database": null, + "schema": "dev", + "name": "hourly_activity_with_daily_context", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/hourly_activity_with_daily_context.sql", + "original_file_path": "models/marts/hourly_activity_with_daily_context.sql", + "unique_id": "model.waffle_shop.hourly_activity_with_daily_context", + "fqn": [ + "waffle_shop", + "models", + "marts", + "hourly_activity_with_daily_context" + ], + "alias": "hourly_activity_with_daily_context", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts", + "acceptance" + ], + "description": "Hourly downstream microbatch model that depends on a coarser-grain daily upstream.", + "columns": { + "activity_hour": { + "name": "activity_hour", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.hourly_activity_with_daily_context", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.hourly_order_activity", + "model.waffle_shop.daily_order_rollup" + ] + } + }, + "model.waffle_shop.hourly_order_activity": { + "database": null, + "schema": "dev", + "name": "hourly_order_activity", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/hourly_order_activity.sql", + "original_file_path": "models/marts/hourly_order_activity.sql", + "unique_id": "model.waffle_shop.hourly_order_activity", + "fqn": [ + "waffle_shop", + "models", + "marts", + "hourly_order_activity" + ], + "alias": "hourly_order_activity", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Hourly order activity aggregated via microbatch incremental.", + "columns": { + "activity_hour": { + "name": "activity_hour", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.hourly_order_activity", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.stg_customers": { + "database": null, + "schema": "dev", + "name": "stg_customers", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_customers.sql", + "original_file_path": "models/staging/stg_customers.sql", + "unique_id": "model.waffle_shop.stg_customers", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_customers" + ], + "alias": "stg_customers", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned customer records.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "email": { + "name": "email", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.stg_customers", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw__customers" + ] + } + }, + "model.waffle_shop.stg_orders": { + "database": null, + "schema": "dev", + "name": "stg_orders", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.waffle_shop.stg_orders", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned order records.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw__orders" + ] + } + }, + "model.waffle_shop.stg_payments": { + "database": null, + "schema": "dev", + "name": "stg_payments", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_payments.sql", + "original_file_path": "models/staging/stg_payments.sql", + "unique_id": "model.waffle_shop.stg_payments", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_payments" + ], + "alias": "stg_payments", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned payment records.", + "columns": { + "payment_id": { + "name": "payment_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.stg_payments", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw__payments" + ] + } + }, + "seed.waffle_shop.waffle_types": { + "database": null, + "schema": "dev", + "name": "waffle_types", + "resource_type": "seed", + "package_name": "waffle_shop", + "path": "seeds/waffle_types.csv", + "original_file_path": "seeds/waffle_types.csv", + "unique_id": "seed.waffle_shop.waffle_types", + "fqn": [ + "waffle_shop", + "seeds", + "waffle_types" + ], + "alias": "waffle_types", + "config": { + "enabled": true, + "alias": null, + "schema": "dev", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Waffle menu items with pricing.", + "columns": { + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_name": { + "name": "waffle_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "category": { + "name": "category", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "price_cents": { + "name": "price_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "dev.waffle_types", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.waffle_shop.raw__customers": { + "database": null, + "schema": "dev", + "name": "raw__customers", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw__customers", + "fqn": [ + "waffle_shop", + "raw__customers" + ], + "source_name": "raw__customers", + "source_description": "", + "loader": "", + "identifier": "raw__customers", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Raw customer records loaded by the Python loader", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "first_name": { + "name": "first_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "last_name": { + "name": "last_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "email": { + "name": "email", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw__customers", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.waffle_shop.raw__orders": { + "database": null, + "schema": "dev", + "name": "raw__orders", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw__orders", + "fqn": [ + "waffle_shop", + "raw__orders" + ], + "source_name": "raw__orders", + "source_description": "", + "loader": "", + "identifier": "raw__orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Raw order records loaded by the Python loader", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "quantity": { + "name": "quantity", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "ordered_at": { + "name": "ordered_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw__orders", + "auto_load": false, + "write_strategy": "delete_insert", + "cursor_column": "ordered_at" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.waffle_shop.raw__payments": { + "database": null, + "schema": "", + "name": "raw__payments", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw__payments", + "fqn": [ + "waffle_shop", + "raw__payments" + ], + "source_name": "raw__payments", + "source_description": "", + "loader": "", + "identifier": "raw__payments", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Payment records for each order, defined inline", + "columns": { + "amount_cents": { + "name": "amount_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.waffle_shop.line_total_cents": { + "name": "line_total_cents", + "resource_type": "macro", + "package_name": "waffle_shop", + "path": "macros/currency.py", + "original_file_path": "macros/currency.py", + "unique_id": "macro.waffle_shop.line_total_cents", + "macro_sql": "\"\"\"Project-wide currency macros.\"\"\"\n\n\ndef line_total_cents(price_cents: str, quantity: str) -> str:\n \"\"\"Calculate line total cents from a unit price and quantity.\"\"\"\n return f\"{price_cents} * {quantity}\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.waffle_shop.cents_to_dollars": { + "name": "cents_to_dollars", + "resource_type": "macro", + "package_name": "waffle_shop", + "path": "models/marts/_sqlbuild/_macros/currency.py", + "original_file_path": "models/marts/_sqlbuild/_macros/currency.py", + "unique_id": "macro.waffle_shop.cents_to_dollars", + "macro_sql": "\"\"\"Currency formatting macros.\"\"\"\n\n\ndef cents_to_dollars(column: str) -> str:\n \"\"\"Convert a cents integer column to a dollars decimal with two decimal places.\"\"\"\n return f\"ROUND(({column}) / 100.0, 2)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.waffle_shop.timestamp_trunc": { + "name": "timestamp_trunc", + "resource_type": "macro", + "package_name": "waffle_shop", + "path": "models/marts/_sqlbuild/_macros/datetime.py", + "original_file_path": "models/marts/_sqlbuild/_macros/datetime.py", + "unique_id": "macro.waffle_shop.timestamp_trunc", + "macro_sql": "\"\"\"Datetime portability macros.\"\"\"\n\n\ndef timestamp_trunc(ctx, grain: str, expr: str) -> str:\n if ctx.adapter_name == \"bigquery\":\n return f\"TIMESTAMP_TRUNC({expr}, {grain.upper()})\"\n return f\"DATE_TRUNC('{grain}', {expr})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.waffle_shop.customer_status_snapshot": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.order_status_index": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.daily_order_partitioned": [ + "model.waffle_shop.stg_orders" + ], + "model.waffle_shop.daily_order_rollup": [ + "model.waffle_shop.hourly_order_activity" + ], + "model.waffle_shop.daily_revenue": [ + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.dim_customers": [ + "model.waffle_shop.stg_customers", + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.fact_orders": [ + "model.waffle_shop.udf__is_completed_order", + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.hourly_activity_with_daily_context": [ + "model.waffle_shop.hourly_order_activity", + "model.waffle_shop.daily_order_rollup" + ], + "model.waffle_shop.hourly_order_activity": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.stg_customers": [ + "source.waffle_shop.raw__customers" + ], + "model.waffle_shop.stg_orders": [ + "source.waffle_shop.raw__orders" + ], + "model.waffle_shop.stg_payments": [ + "source.waffle_shop.raw__payments" + ], + "source.waffle_shop.raw__customers": [], + "source.waffle_shop.raw__orders": [], + "source.waffle_shop.raw__payments": [], + "seed.waffle_shop.waffle_types": [], + "model.waffle_shop.table_fn__customer_orders": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.udf__is_completed_order": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-accepted-values-type.json b/tests/goldens/compiler/failure/analysis-accepted-values-type.json new file mode 100644 index 0000000000..15c849fec9 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-accepted-values-type.json @@ -0,0 +1,308 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B301", + "message": "accepted_values: IN list contains an invalid coercible literal", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 5, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 5 + }, + "help": "align this declared metadata or audit value with the column or argument type" + }, + { + "phase": "compile", + "severity": "error", + "code": "B218", + "message": "audit 'accepted_values' on model 'customer_totals' column 'customer_id': IN list contains an invalid coercible literal", + "resource_type": "audit", + "resource_name": "accepted_values", + "path": "audits/generic/accepted_values.sql", + "line": 6, + "column": 30, + "location": { + "path": "audits/generic/accepted_values.sql", + "line": 6, + "column": 30, + "end_line": 7, + "end_column": 8 + }, + "help": "choose a supported source-to-target cast for this dialect" + } + ] + } + ], + "compiled": { + "audits/generic/customer_totals/accepted_values__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"customer_totals\")", + "WHERE customer_id IS NOT NULL", + " AND customer_id NOT IN ('DATE', '2026-01-01')", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-aggregate-in-where.json b/tests/goldens/compiler/failure/analysis-aggregate-in-where.json new file mode 100644 index 0000000000..773acca307 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-aggregate-in-where.json @@ -0,0 +1,275 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B231", + "message": "Aggregate function is not allowed in this clause or inside another aggregate", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 11, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 11, + "end_line": 7, + "end_column": 17 + }, + "help": "move this aggregate to SELECT or HAVING, or compute it in an input CTE" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_orders\")", + "WHERE SUM(amount) > 1", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-alias-column-list-width.json b/tests/goldens/compiler/failure/analysis-alias-column-list-width.json new file mode 100644 index 0000000000..119220384a --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-alias-column-list-width.json @@ -0,0 +1,273 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B005", + "message": "Derived-table column alias count exceeds its output column count", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 73, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 73, + "end_line": 6, + "end_column": 74 + }, + "help": "match the relation alias list to its available output columns" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT o.a AS first_column", + "FROM (SELECT order_id, customer_id FROM __ref(\"stg_orders\")) AS o(a, b, c)", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-ambiguous-column.json b/tests/goldens/compiler/failure/analysis-ambiguous-column.json new file mode 100644 index 0000000000..56297788ab --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-ambiguous-column.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B003", + "message": "Ambiguous unqualified column 'order_id' found in 2 referenced tables", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 16 + }, + "help": "qualify this column with the intended input alias" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_orders\") a", + "JOIN __ref(\"stg_orders\") b ON a.customer_id = b.customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-arithmetic-operands.json b/tests/goldens/compiler/failure/analysis-arithmetic-operands.json new file mode 100644 index 0000000000..eb60410254 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-arithmetic-operands.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B212", + "message": "Arithmetic operation expects NUMERIC-compatible operands, found STRING and INTEGER", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "end_line": 5, + "end_column": 31 + }, + "help": "use operands supported by this arithmetic operator, or convert them explicitly", + "notes": [ + "status is TEXT, 1 is INTEGER" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, status + 1 AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-cursor-type-family.json b/tests/goldens/compiler/failure/analysis-cursor-type-family.json new file mode 100644 index 0000000000..207baf4a14 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-cursor-type-family.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B301", + "message": "cursor_type TIMESTAMP does not match column 'customer_id' type INT", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 15, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 15 + }, + "help": "align this declared metadata or audit value with the column or argument type" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "customer_id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-duplicate-cte-name.json b/tests/goldens/compiler/failure/analysis-duplicate-cte-name.json new file mode 100644 index 0000000000..ac30091e30 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-duplicate-cte-name.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B233", + "message": "Duplicate CTE name 'totals'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 8, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 8, + "end_line": 7, + "end_column": 19 + }, + "help": "use distinct names for relations or CTEs within this scope" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "WITH totals AS (SELECT customer_id FROM __ref(\"stg_orders\")),", + "totals AS (SELECT customer_id FROM __ref(\"stg_orders\"))", + "SELECT customer_id FROM totals", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-expression-audit-unknown-column.json b/tests/goldens/compiler/failure/analysis-expression-audit-unknown-column.json new file mode 100644 index 0000000000..c34e4d80c9 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-expression-audit-unknown-column.json @@ -0,0 +1,295 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'discount' in output", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 43, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 43 + } + }, + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "audit 'expression_is_true' on model 'customer_totals': Unknown column 'discount' in table 'customer_totals' (context: WHERE)", + "resource_type": "audit", + "resource_name": "expression_is_true", + "path": "models/marts/_sqlbuild/_audits/generic/expression_is_true.sql", + "line": 5, + "column": 21, + "location": { + "path": "models/marts/_sqlbuild/_audits/generic/expression_is_true.sql", + "line": 5, + "column": 21, + "end_line": 6, + "end_column": 5 + } + } + ] + } + ], + "compiled": { + "audits/generic/customer_totals/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"customer_totals\")", + "WHERE NOT (discount >= 0)", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-function-argument-count.json b/tests/goldens/compiler/failure/analysis-function-argument-count.json new file mode 100644 index 0000000000..f4a1354727 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-function-argument-count.json @@ -0,0 +1,273 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B102", + "message": "Invalid arity for function 'SUBSTRING': got 1, expected 2, 3", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 31, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 31, + "end_line": 5, + "end_column": 37 + }, + "help": "pass the number of arguments required by this function's signature" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUBSTRING(status) AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-function-argument-type.json b/tests/goldens/compiler/failure/analysis-function-argument-type.json new file mode 100644 index 0000000000..1e1430c78f --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-function-argument-type.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B213", + "message": "Function 'abs' argument 1 expects NUMERIC, found STRING", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "end_line": 5, + "end_column": 31 + }, + "help": "supply argument types supported by this function or conditional expression", + "notes": [ + "status is TEXT" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, ABS(status) AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-non-boolean-predicate.json b/tests/goldens/compiler/failure/analysis-non-boolean-predicate.json new file mode 100644 index 0000000000..5f5423e60c --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-non-boolean-predicate.json @@ -0,0 +1,277 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B211", + "message": "WHERE expects a BOOLEAN predicate, found STRING", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 13 + }, + "help": "use a Boolean predicate in this condition", + "notes": [ + "status is TEXT" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, amount AS total_amount", + "FROM __ref(\"stg_orders\")", + "WHERE status", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-non-constant-limit.json b/tests/goldens/compiler/failure/analysis-non-constant-limit.json new file mode 100644 index 0000000000..6d7372cef6 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-non-constant-limit.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B234", + "message": "LIMIT/OFFSET must be a non-negative constant NUMERIC expression", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 18 + }, + "help": "use a valid constant bound for LIMIT or OFFSET" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_orders\")", + "LIMIT customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-opt-out-conflicts-with-legacy-key.json b/tests/goldens/compiler/failure/analysis-opt-out-conflicts-with-legacy-key.json new file mode 100644 index 0000000000..fe9f4466a9 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-opt-out-conflicts-with-legacy-key.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P003", + "message": "MODEL sql_analysis conflicts with legacy sql_validation" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/analysis-rejected-opt-out-hides-findings.json b/tests/goldens/compiler/failure/analysis-rejected-opt-out-hides-findings.json new file mode 100644 index 0000000000..4f7a31b683 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-rejected-opt-out-hides-findings.json @@ -0,0 +1,275 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P009", + "message": "`sql_analysis false` is not needed for model 'customer_totals'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 3, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 3 + }, + "help": "remove `sql_analysis false` and fix the findings it was hiding: 1 unknown column (run `sqb compile` to see them)\n = help: to allow `sql_analysis false` on any model, SQL test or audit, set this in sqlbuild_project.toml:\n [settings]\n require_sql_analysis = false", + "notes": [ + "sqlbuild_project.toml sets [settings] require_sql_analysis = true, which only allows `sql_analysis false` on SQL that SQLBuild cannot parse; this model parses successfully." + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(refund) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-relationships-unknown-field.json b/tests/goldens/compiler/failure/analysis-relationships-unknown-field.json new file mode 100644 index 0000000000..eea8403898 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-relationships-unknown-field.json @@ -0,0 +1,329 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "relationships target has no column 'customer_key'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 71, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 71 + }, + "help": "change the metadata column name to an existing output column" + }, + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "audit 'relationships' on model 'customer_totals' column 'customer_id': Unknown column 'customer_key' in table 'stg_orders' (context: SELECT)", + "resource_type": "audit", + "resource_name": "relationships", + "path": "audits/generic/relationships.sql", + "line": 9, + "column": 8, + "location": { + "path": "audits/generic/relationships.sql", + "line": 9, + "column": 8, + "end_line": 9, + "end_column": 20 + } + }, + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "audit 'relationships' on model 'customer_totals' column 'customer_id': Unknown column 'customer_key' in table 'stg_orders' (context: SELECT)", + "resource_type": "audit", + "resource_name": "relationships", + "path": "audits/generic/relationships.sql", + "line": 11, + "column": 27, + "location": { + "path": "audits/generic/relationships.sql", + "line": 11, + "column": 27, + "end_line": 11, + "end_column": 39 + } + } + ] + } + ], + "compiled": { + "audits/generic/customer_totals/relationships__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"customer_totals\")", + "WHERE customer_id IS NOT NULL", + " AND customer_id NOT IN (", + " SELECT customer_key", + " FROM __ref(\"stg_orders\")", + " WHERE customer_key IS NOT NULL", + " )", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-cte-chain-unknown-column.json b/tests/goldens/compiler/failure/analysis-session-cte-chain-unknown-column.json new file mode 100644 index 0000000000..a06ea313c2 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-cte-chain-unknown-column.json @@ -0,0 +1,273 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'order_count' in totals", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 35, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 35, + "end_line": 7, + "end_column": 46 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "WITH base AS (SELECT * FROM __ref(\"stg_orders\")),", + "totals AS (SELECT customer_id, SUM(amount) AS total_amount FROM base GROUP BY 1)", + "SELECT customer_id, total_amount, order_count FROM totals", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-cte-fact-nullability.json b/tests/goldens/compiler/failure/analysis-session-cte-fact-nullability.json new file mode 100644 index 0000000000..501ce3c08c --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-cte-fact-nullability.json @@ -0,0 +1,309 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K004", + "message": "column 'note' is declared non-null but may be nullable", + "resource_type": "model", + "resource_name": "customer_totals", + "column_name": "note", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 9 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/marts/customer_totals.sql", + "line": 14, + "column": 40, + "end_line": 14, + "end_column": 44 + }, + "message": "output expression proven nullable" + } + ], + "help": "use COALESCE, filter nulls explicitly, or remove the non-null contract" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "WITH base AS (", + " SELECT customer_id, CAST(NULL AS VARCHAR) AS note", + " FROM __ref(\"stg_orders\")", + ")", + "SELECT customer_id + 0 AS customer_id, note FROM base", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "note": { + "name": "note", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-cte-fact-type-mismatch.json b/tests/goldens/compiler/failure/analysis-session-cte-fact-type-mismatch.json new file mode 100644 index 0000000000..3e09c1bcdc --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-cte-fact-type-mismatch.json @@ -0,0 +1,309 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'total_amount' inferred as DOUBLE but declared type is VARCHAR", + "resource_type": "model", + "resource_name": "customer_totals", + "column_name": "total_amount", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 17 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/marts/customer_totals.sql", + "line": 14, + "column": 40, + "end_line": 14, + "end_column": 52 + }, + "message": "inferred DOUBLE" + } + ], + "help": "change the declared type or cast the expression explicitly" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "WITH totals AS (", + " SELECT customer_id, CAST(amount AS DOUBLE) AS total_amount", + " FROM __ref(\"stg_orders\")", + ")", + "SELECT customer_id + 0 AS customer_id, total_amount FROM totals", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "total_amount": { + "name": "total_amount", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-enriched-subquery-type-mismatch.json b/tests/goldens/compiler/failure/analysis-session-enriched-subquery-type-mismatch.json new file mode 100644 index 0000000000..346bfa9476 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-enriched-subquery-type-mismatch.json @@ -0,0 +1,306 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'amount' inferred as DOUBLE but declared type is VARCHAR", + "resource_type": "model", + "resource_name": "customer_totals", + "column_name": "amount", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 11 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/marts/customer_totals.sql", + "line": 10, + "column": 21, + "end_line": 10, + "end_column": 27 + }, + "message": "inferred DOUBLE" + } + ], + "help": "change the declared type or cast the expression explicitly" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, amount", + "FROM (SELECT * FROM __ref(\"stg_orders\")) staged", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-pivot-family-column-mismatch.json b/tests/goldens/compiler/failure/analysis-session-pivot-family-column-mismatch.json new file mode 100644 index 0000000000..c4e0b17259 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-pivot-family-column-mismatch.json @@ -0,0 +1,367 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'status_amounts' dynamic column contract is not proven: dynamic family 'status_amounts' declares pivot_column 'region' but the output pivot uses 'status'", + "resource_type": "model", + "resource_name": "status_amounts", + "path": "models/marts/status_amounts.sql", + "help": "project one supported runtime-dynamic pivot through a wildcard output boundary and declare every generated family" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/status_amounts.sql": [ + "PIVOT __source(\"raw_orders\")", + "ON status", + "USING MAX(amount)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.status_amounts": { + "database": null, + "schema": "main", + "name": "status_amounts", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/status_amounts.sql", + "original_file_path": "models/marts/status_amounts.sql", + "unique_id": "model.failure_corpus.status_amounts", + "fqn": [ + "failure_corpus", + "models", + "marts", + "status_amounts" + ], + "alias": "status_amounts", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order amounts pivoted by status", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "region", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.status_amounts", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.status_amounts": [ + "source.failure_corpus.raw_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-pivot-values-on-clause.json b/tests/goldens/compiler/failure/analysis-session-pivot-values-on-clause.json new file mode 100644 index 0000000000..830a05d90f --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-pivot-values-on-clause.json @@ -0,0 +1,367 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'status_amounts' dynamic column contract is not proven: dynamic column contracts currently require exactly one pivot column", + "resource_type": "model", + "resource_name": "status_amounts", + "path": "models/marts/status_amounts.sql", + "help": "project one supported runtime-dynamic pivot through a wildcard output boundary and declare every generated family" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/status_amounts.sql": [ + "PIVOT __source(\"raw_orders\")", + "ON status IN ('placed')", + "USING MAX(amount)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.status_amounts": { + "database": null, + "schema": "main", + "name": "status_amounts", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/status_amounts.sql", + "original_file_path": "models/marts/status_amounts.sql", + "unique_id": "model.failure_corpus.status_amounts", + "fqn": [ + "failure_corpus", + "models", + "marts", + "status_amounts" + ], + "alias": "status_amounts", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order amounts pivoted by status", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.status_amounts", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.status_amounts": [ + "source.failure_corpus.raw_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-set-operation-unknown-column.json b/tests/goldens/compiler/failure/analysis-session-set-operation-unknown-column.json new file mode 100644 index 0000000000..3ad0352ce1 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-set-operation-unknown-column.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'refund_amount' in stg_orders", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 21, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 21, + "end_line": 7, + "end_column": 34 + }, + "notes": [ + "stg_orders has: amount, status, customer_id, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, amount AS total_amount FROM __ref(\"stg_orders\")", + "UNION ALL", + "SELECT customer_id, refund_amount FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-session-star-published-unknown-column.json b/tests/goldens/compiler/failure/analysis-session-star-published-unknown-column.json new file mode 100644 index 0000000000..496a2c776b --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-session-star-published-unknown-column.json @@ -0,0 +1,353 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'missing_amount' in order_layers", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "end_line": 5, + "end_column": 39 + }, + "notes": [ + "order_layers has: doubled_amount, amount, status, customer_id, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(missing_amount) AS total_amount", + "FROM __ref(\"order_layers\")", + "GROUP BY customer_id", + "" + ], + "models/marts/order_layers.sql": [ + "SELECT s.*, s.amount * 2 AS doubled_amount", + "FROM __ref(\"stg_orders\") s", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT *", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.order_layers" + ] + } + }, + "model.failure_corpus.order_layers": { + "database": null, + "schema": "main", + "name": "order_layers", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/order_layers.sql", + "original_file_path": "models/marts/order_layers.sql", + "unique_id": "model.failure_corpus.order_layers", + "fqn": [ + "failure_corpus", + "models", + "marts", + "order_layers" + ], + "alias": "order_layers", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Orders layered over the staged star", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.order_layers", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.order_layers" + ], + "model.failure_corpus.order_layers": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-set-operation-branch-types.json b/tests/goldens/compiler/failure/analysis-set-operation-branch-types.json new file mode 100644 index 0000000000..a4037c2270 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-set-operation-branch-types.json @@ -0,0 +1,272 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B215", + "message": "UNION column 2 has incompatible types: NUMERIC vs DATE", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1 + }, + "help": "align the corresponding types in each set-operation branch" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, amount FROM __ref(\"stg_orders\")", + "UNION ALL", + "SELECT customer_id, DATE '2026-01-01' FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-test-fixture-unknown-column.json b/tests/goldens/compiler/failure/analysis-test-fixture-unknown-column.json new file mode 100644 index 0000000000..a984fd998d --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-test-fixture-unknown-column.json @@ -0,0 +1,283 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B302", + "message": "SQL test '__source__raw_orders' names unknown column 'discount'", + "resource_type": "sql_test", + "resource_name": "test_stg_orders", + "path": "tests/unit/test_stg_orders.sql", + "line": 5, + "column": 98, + "location": { + "path": "tests/unit/test_stg_orders.sql", + "line": 5, + "column": 98, + "end_line": 5, + "end_column": 106 + }, + "help": "align the SQL-test fixture or expected columns with the tested resource's output" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ], + "tests/stg_orders/test_stg_orders.sql": [ + "WITH __source__raw_orders AS (SELECT 1 AS order_id, 10 AS customer_id, CAST(5 AS DOUBLE) AS amount, 'placed' AS status, 2 AS discount),", + "__ref__stg_orders AS (SELECT order_id, customer_id, amount, status", + "FROM __source__raw_orders),", + "__actual__stg_orders AS (SELECT * FROM __ref__stg_orders),", + "__expected__stg_orders AS (SELECT 1 AS order_id)", + "SELECT 0 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id FROM __actual__stg_orders EXCEPT SELECT order_id FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id FROM __expected__stg_orders EXCEPT SELECT order_id FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-udf-argument-count.json b/tests/goldens/compiler/failure/analysis-udf-argument-count.json new file mode 100644 index 0000000000..58323fe460 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-udf-argument-count.json @@ -0,0 +1,280 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B102", + "message": "Function 'scaled_amount' expects 2 arguments but received 1", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 28, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 28 + }, + "help": "pass the number of arguments required by this function's signature" + } + ] + } + ], + "compiled": { + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE MACRO main.scaled_amount(p_amount, p_factor) AS (", + "p_amount * p_factor", + ")", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, __udf(\"scaled_amount\")(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [], + "model.failure_corpus.scaled_amount": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-udf-argument-family.json b/tests/goldens/compiler/failure/analysis-udf-argument-family.json new file mode 100644 index 0000000000..6bb4f4a102 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-udf-argument-family.json @@ -0,0 +1,280 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B301", + "message": "Function 'scaled_amount' argument 'p_amount' expects DOUBLE, received TEXT; convert the argument explicitly", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 28, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 28 + }, + "help": "align this declared metadata or audit value with the column or argument type" + } + ] + } + ], + "compiled": { + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE MACRO main.scaled_amount(p_amount, p_factor) AS (", + "p_amount * p_factor", + ")", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, __udf(\"scaled_amount\")(status, 2) AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [], + "model.failure_corpus.scaled_amount": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-unique-key-unknown-column.json b/tests/goldens/compiler/failure/analysis-unique-key-unknown-column.json new file mode 100644 index 0000000000..ca04c7c838 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-unique-key-unknown-column.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "unique_key references unknown column 'order_key'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 15, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 15 + }, + "help": "change the metadata column name to an existing output column" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "order_key" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-unknown-function.json b/tests/goldens/compiler/failure/analysis-unknown-function.json new file mode 100644 index 0000000000..6f34c1a3a8 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-unknown-function.json @@ -0,0 +1,273 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B101", + "message": "Unknown function 'not_a_function' for dialect DuckDB", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 36, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 36, + "end_line": 5, + "end_column": 42 + }, + "help": "check the function spelling or declare the project function before using it" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, not_a_function(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-unknown-qualifier.json b/tests/goldens/compiler/failure/analysis-unknown-qualifier.json new file mode 100644 index 0000000000..a9ba57f63f --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-unknown-qualifier.json @@ -0,0 +1,273 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B004", + "message": "Unknown table or alias 'x' referenced by column 'order_id'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 9 + }, + "help": "give each referenced relation a visible alias in this scope" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT x.order_id", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-unsupported-cast.json b/tests/goldens/compiler/failure/analysis-unsupported-cast.json new file mode 100644 index 0000000000..413dbe4691 --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-unsupported-cast.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B218", + "message": "Invalid temporal literal", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "end_line": 5, + "end_column": 38 + }, + "help": "choose a supported source-to-target cast for this dialect", + "notes": [ + "DATE '2026-13-45' is DATE" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, DATE '2026-13-45' AS placed_on", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/analysis-window-without-over.json b/tests/goldens/compiler/failure/analysis-window-without-over.json new file mode 100644 index 0000000000..b9762e9a4f --- /dev/null +++ b/tests/goldens/compiler/failure/analysis-window-without-over.json @@ -0,0 +1,271 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B232", + "message": "Window function requires an OVER clause", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1 + }, + "help": "use this window function with a valid OVER clause and window context" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, ROW_NUMBER() AS position", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/assembly-hook-syntax-unbuilt-dialect.json b/tests/goldens/compiler/failure/assembly-hook-syntax-unbuilt-dialect.json new file mode 100644 index 0000000000..e1bd80236f --- /dev/null +++ b/tests/goldens/compiler/failure/assembly-hook-syntax-unbuilt-dialect.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Polyglot could not parse model 'customer_totals' post_hooks[0] inline_sql(\"...\") (/models/marts/customer_totals.sql): Invalid expression / Unexpected token", + "help": "if this SQL is valid for your warehouse, skip SQL analysis for this model, add this to the MODEL header:\n MODEL (\n sql_analysis false,\n ...\n );\n and please report the SQL so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/attached-audit-reads-dependant.json b/tests/goldens/compiler/failure/attached-audit-reads-dependant.json new file mode 100644 index 0000000000..e49035df7a --- /dev/null +++ b/tests/goldens/compiler/failure/attached-audit-reads-dependant.json @@ -0,0 +1,271 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P005", + "message": "Audit 'matches_totals' on model 'stg_orders' reads model 'customer_totals', which depends on 'stg_orders'; an attached audit gates its target, so it cannot wait for a resource built from that target", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/_sqlbuild/_audits/generic/matches_totals.sql", + "help": "write a singular audit under audits/singular/ that references both 'stg_orders' and 'customer_totals'; it runs once both are built" + } + ] + } + ], + "compiled": { + "audits/generic/stg_orders/matches_totals.sql": [ + "SELECT *", + "FROM __ref(\"stg_orders\") o", + "WHERE o.customer_id NOT IN (SELECT customer_id FROM __ref(\"customer_totals\"))", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/audit-parse.json b/tests/goldens/compiler/failure/audit-parse.json new file mode 100644 index 0000000000..2804df5d96 --- /dev/null +++ b/tests/goldens/compiler/failure/audit-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D004", + "message": "AUDIT(...) in '/models/marts/_sqlbuild/audits/singular/broken.sql' contains invalid SQLBuild header syntax: unexpected token 'name' without a value; quote values with spaces" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/audit-role-unsupported-entry.json b/tests/goldens/compiler/failure/audit-role-unsupported-entry.json new file mode 100644 index 0000000000..9d174e5294 --- /dev/null +++ b/tests/goldens/compiler/failure/audit-role-unsupported-entry.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Unsupported entries in audits/: audits/at_least.sql; audit files must live in audits/generic/ or audits/singular/" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/audit-unknown-project-variable.json b/tests/goldens/compiler/failure/audit-unknown-project-variable.json new file mode 100644 index 0000000000..3525ad0f6b --- /dev/null +++ b/tests/goldens/compiler/failure/audit-unknown-project-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown project variable '@@floor_amount' in '/models/staging/_sqlbuild/_audits/generic/floor.sql'. Available vars: region" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/audit-variable-in-doubled-backticks.json b/tests/goldens/compiler/failure/audit-variable-in-doubled-backticks.json new file mode 100644 index 0000000000..3525ad0f6b --- /dev/null +++ b/tests/goldens/compiler/failure/audit-variable-in-doubled-backticks.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown project variable '@@floor_amount' in '/models/staging/_sqlbuild/_audits/generic/floor.sql'. Available vars: region" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/built-in-audit-shadow.json b/tests/goldens/compiler/failure/built-in-audit-shadow.json new file mode 100644 index 0000000000..eda200b8ff --- /dev/null +++ b/tests/goldens/compiler/failure/built-in-audit-shadow.json @@ -0,0 +1,279 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "warning", + "code": "P003", + "message": "project audit 'not_null' overrides built-in audit 'not_null'", + "path": "models/staging/_sqlbuild/_audits/generic/not_null.sql", + "help": "rename the project audit if this override is unintended" + }, + { + "phase": "compile", + "severity": "error", + "code": "S010", + "message": "Unused local declaration 'audit:not_null' at models/staging/_sqlbuild/_audits/generic/not_null.sql; remove it or add a genuine runtime use", + "resource_type": "audit", + "resource_name": "not_null", + "path": "models/staging/_sqlbuild/_audits/generic/not_null.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/_sqlbuild/_audits/generic/not_null.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/check-depends-on-check.json b/tests/goldens/compiler/failure/check-depends-on-check.json new file mode 100644 index 0000000000..79039c3ed2 --- /dev/null +++ b/tests/goldens/compiler/failure/check-depends-on-check.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Check 'orders_checked' depends on another check; checks may depend on loaders, tasks, assets, models, sources, and seeds only" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/column-nullable-not-null.json b/tests/goldens/compiler/failure/column-nullable-not-null.json new file mode 100644 index 0000000000..967e247e56 --- /dev/null +++ b/tests/goldens/compiler/failure/column-nullable-not-null.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P002", + "message": "models/staging/stg_orders.sql column 'order_id' cannot set nullable = true and audit not_null", + "help": "remove the not_null audit or set nullable = false" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/command-output-sink-unknown-provider.json b/tests/goldens/compiler/failure/command-output-sink-unknown-provider.json new file mode 100644 index 0000000000..9fb21e36bd --- /dev/null +++ b/tests/goldens/compiler/failure/command-output-sink-unknown-provider.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D015", + "message": "Command-output sink 'publish_output' in sinks/output.py requires unknown provider 'destination_client'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/commented-ref-argument.json b/tests/goldens/compiler/failure/commented-ref-argument.json new file mode 100644 index 0000000000..c4d7ff89d0 --- /dev/null +++ b/tests/goldens/compiler/failure/commented-ref-argument.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref( /* upstream */ 'stg_orders') is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 41 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"stg_orders\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref( /* upstream */ 'stg_orders')", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/comparison-type.json b/tests/goldens/compiler/failure/comparison-type.json new file mode 100644 index 0000000000..51fbf222ca --- /dev/null +++ b/tests/goldens/compiler/failure/comparison-type.json @@ -0,0 +1,278 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B217", + "message": "Incompatible comparison between NUMERIC and DATE", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 33 + }, + "help": "compare with a date, for example DATE '2026-04-01'", + "notes": [ + "amount is DOUBLE, DATE '2026-01-01' is DATE" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "WHERE amount = DATE '2026-01-01'", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/config-bom.json b/tests/goldens/compiler/failure/config-bom.json new file mode 100644 index 0000000000..e2af44d5b4 --- /dev/null +++ b/tests/goldens/compiler/failure/config-bom.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_project.toml contains invalid TOML: Invalid statement (at line 1, column 1)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-concurrency-without-capability.json b/tests/goldens/compiler/failure/config-concurrency-without-capability.json new file mode 100644 index 0000000000..72b28b51ed --- /dev/null +++ b/tests/goldens/compiler/failure/config-concurrency-without-capability.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': batch_concurrency > 1 requires incremental_mode=microbatch" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-cursor-bound-outside-utc-years.json b/tests/goldens/compiler/failure/config-cursor-bound-outside-utc-years.json new file mode 100644 index 0000000000..b933cf121d --- /dev/null +++ b/tests/goldens/compiler/failure/config-cursor-bound-outside-utc-years.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': cursor_start value '0001-01-01T00:00:00+01:00' falls outside years 1-9999 once converted to UTC", + "help": "keep cursor_start within years 1-9999 in UTC, add this to the MODEL header:\n MODEL (\n cursor_start '0001-01-01T00:00:00+00:00',\n ...\n );" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-cursor-bounds-reversed.json b/tests/goldens/compiler/failure/config-cursor-bounds-reversed.json new file mode 100644 index 0000000000..219673ce50 --- /dev/null +++ b/tests/goldens/compiler/failure/config-cursor-bounds-reversed.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': cursor_start must be before exclusive cursor_end" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-equally-specific-path-defaults.json b/tests/goldens/compiler/failure/config-equally-specific-path-defaults.json new file mode 100644 index 0000000000..3055d01eee --- /dev/null +++ b/tests/goldens/compiler/failure/config-equally-specific-path-defaults.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Model path 'staging/stg_orders.sql' matches equally specific path_defaults keys: '*/stg_orders.sql', 'staging/*'.", + "help": "Make one pattern narrower by adding literal or '*' path segments, or remove the overlap. Path-default selection never depends on declaration order." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-header-tags-not-list.json b/tests/goldens/compiler/failure/config-header-tags-not-list.json new file mode 100644 index 0000000000..e5bf494b08 --- /dev/null +++ b/tests/goldens/compiler/failure/config-header-tags-not-list.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders' tags must be a list" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-incremental-key-on-table.json b/tests/goldens/compiler/failure/config-incremental-key-on-table.json new file mode 100644 index 0000000000..27e5f2e87a --- /dev/null +++ b/tests/goldens/compiler/failure/config-incremental-key-on-table.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': on_schema_change is only valid for incremental models" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-incremental-without-strategy.json b/tests/goldens/compiler/failure/config-incremental-without-strategy.json new file mode 100644 index 0000000000..4e834f3909 --- /dev/null +++ b/tests/goldens/compiler/failure/config-incremental-without-strategy.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': incremental materialization requires incremental_strategy" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-macro-outside-hooks.json b/tests/goldens/compiler/failure/config-macro-outside-hooks.json new file mode 100644 index 0000000000..469e811060 --- /dev/null +++ b/tests/goldens/compiler/failure/config-macro-outside-hooks.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config field 'alias' does not allow macros" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-merge-exclusion-overlaps-key.json b/tests/goldens/compiler/failure/config-merge-exclusion-overlaps-key.json new file mode 100644 index 0000000000..0ce60aa3f5 --- /dev/null +++ b/tests/goldens/compiler/failure/config-merge-exclusion-overlaps-key.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': merge_exclude_columns cannot include unique_key column(s): ORDER_ID" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-microbatch-without-strategy.json b/tests/goldens/compiler/failure/config-microbatch-without-strategy.json new file mode 100644 index 0000000000..bad4f2e413 --- /dev/null +++ b/tests/goldens/compiler/failure/config-microbatch-without-strategy.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': incremental_mode=microbatch requires explicit microbatch_strategy (rolling_window or watermark)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-migrate-force-on-table.json b/tests/goldens/compiler/failure/config-migrate-force-on-table.json new file mode 100644 index 0000000000..f8d07ab2cc --- /dev/null +++ b/tests/goldens/compiler/failure/config-migrate-force-on-table.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': migrate_force is only valid for incremental and snapshot models; nothing is replaced when a 'table' model migrates, because tables and views are rebuilt under their new name", + "help": "remove migrate_force from the model header" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-old-name-view-without-duration.json b/tests/goldens/compiler/failure/config-old-name-view-without-duration.json new file mode 100644 index 0000000000..53627ed2b4 --- /dev/null +++ b/tests/goldens/compiler/failure/config-old-name-view-without-duration.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': old_name_view must be a positive duration such as 7d, or false; got 'soon'", + "help": "write for example old_name_view 7d, or old_name_view false" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-placeholder-on-built-in-materialization.json b/tests/goldens/compiler/failure/config-placeholder-on-built-in-materialization.json new file mode 100644 index 0000000000..8158924744 --- /dev/null +++ b/tests/goldens/compiler/failure/config-placeholder-on-built-in-materialization.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': @@@placeholders are only allowed on custom materializations" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-retention-not-whole-days.json b/tests/goldens/compiler/failure/config-retention-not-whole-days.json new file mode 100644 index 0000000000..4440debbaf --- /dev/null +++ b/tests/goldens/compiler/failure/config-retention-not-whole-days.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': time_travel_retention must be a whole-day string like '7d', 'inherit', or 'disabled'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-retention-on-view.json b/tests/goldens/compiler/failure/config-retention-on-view.json new file mode 100644 index 0000000000..b9daf2ab2a --- /dev/null +++ b/tests/goldens/compiler/failure/config-retention-on-view.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': managed time_travel_retention is not valid for views; set time_travel_retention disabled" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-several-faults-reports-the-first.json b/tests/goldens/compiler/failure/config-several-faults-reports-the-first.json new file mode 100644 index 0000000000..477aa05f9c --- /dev/null +++ b/tests/goldens/compiler/failure/config-several-faults-reports-the-first.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': table_type must be permanent, transient, or inherit" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-snapshot-without-unique-key.json b/tests/goldens/compiler/failure/config-snapshot-without-unique-key.json new file mode 100644 index 0000000000..431a0ffca7 --- /dev/null +++ b/tests/goldens/compiler/failure/config-snapshot-without-unique-key.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': snapshot materialization requires unique_key" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-missing-environment-variable.json b/tests/goldens/compiler/failure/config-template-missing-environment-variable.json new file mode 100644 index 0000000000..12032faac2 --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-missing-environment-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references missing ENV variable 'SQB_CORPUS_UNSET_SCHEMA'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-unknown-namespace.json b/tests/goldens/compiler/failure/config-template-unknown-namespace.json new file mode 100644 index 0000000000..2700f29bcd --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-unknown-namespace.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references unsupported template namespace 'VAULT'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-unknown-variable.json b/tests/goldens/compiler/failure/config-template-unknown-variable.json new file mode 100644 index 0000000000..72753ad8c6 --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-unknown-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references unknown variable 'missing_region'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-unsupported-function.json b/tests/goldens/compiler/failure/config-template-unsupported-function.json new file mode 100644 index 0000000000..598de35743 --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-unsupported-function.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references unsupported template function 'upper'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-unterminated-string.json b/tests/goldens/compiler/failure/config-template-unterminated-string.json new file mode 100644 index 0000000000..928b630a46 --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-unterminated-string.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "template expression has unterminated single-quoted string at position 9" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-template-wrong-argument-count.json b/tests/goldens/compiler/failure/config-template-wrong-argument-count.json new file mode 100644 index 0000000000..7987f0aa98 --- /dev/null +++ b/tests/goldens/compiler/failure/config-template-wrong-argument-count.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config if(...) expects 3 arguments" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-toml-syntax.json b/tests/goldens/compiler/failure/config-toml-syntax.json new file mode 100644 index 0000000000..3b8eaedf30 --- /dev/null +++ b/tests/goldens/compiler/failure/config-toml-syntax.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_project.toml contains invalid TOML: Expected ']' at the end of a table declaration (at line 6, column 10)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-adapter.json b/tests/goldens/compiler/failure/config-unknown-adapter.json new file mode 100644 index 0000000000..cb53fda78f --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-adapter.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C601", + "message": "unknown adapter 'warehouse9000'. Available built-in adapters: bigquery, databricks, duckdb, motherduck, postgres, snowflake, sqlserver. Project-local adapters are discovered from adapters/**/*.py." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-contract.json b/tests/goldens/compiler/failure/config-unknown-contract.json new file mode 100644 index 0000000000..c92b833472 --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-contract.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': unknown contract 'strict'; valid values: enforced, none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-default-key.json b/tests/goldens/compiler/failure/config-unknown-default-key.json new file mode 100644 index 0000000000..171f6252b1 --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-default-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_project.toml [defaults] contains unknown key(s): description. Allowed keys: append_cursor_inclusive, batch_concurrency, batch_size, contract, cursor_end, cursor_future_action, cursor_future_max_distance, cursor_start, cursor_start_max_action, cursor_start_max_ahead, cursor_watermark_mode, database, full_refresh, function_database, function_schema, incremental_mode, incremental_strategy, lookback, materialized, max_microbatches, merge_exclude_columns, microbatch_strategy, replay_on_change, row_diff_exclude_columns, row_diff_sample_rows, row_diff_sample_seed, row_diff_tolerances, schema, seed_database, seed_schema, tags, unaccounted_partition_policy", + "help": "remove the key; see the reference for supported keys" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-materialization.json b/tests/goldens/compiler/failure/config-unknown-materialization.json new file mode 100644 index 0000000000..bb367cc1c7 --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-materialization.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': unknown materialization 'archive'; not a built-in type and no custom materialization with that name was discovered" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-model-reference.json b/tests/goldens/compiler/failure/config-unknown-model-reference.json new file mode 100644 index 0000000000..e30c3b4ce0 --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-model-reference.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/marts/customer_totals.sql references unknown model 'stg_refunds'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-unknown-table-type.json b/tests/goldens/compiler/failure/config-unknown-table-type.json new file mode 100644 index 0000000000..477aa05f9c --- /dev/null +++ b/tests/goldens/compiler/failure/config-unknown-table-type.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': table_type must be permanent, transient, or inherit" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-untyped-hook-entry.json b/tests/goldens/compiler/failure/config-untyped-hook-entry.json new file mode 100644 index 0000000000..9a008b6060 --- /dev/null +++ b/tests/goldens/compiler/failure/config-untyped-hook-entry.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders' pre_hooks entries must use typed inline_sql(...), sql(...), or python(...) hook syntax" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/config-watermark-limit-below-lookback.json b/tests/goldens/compiler/failure/config-watermark-limit-below-lookback.json new file mode 100644 index 0000000000..3964c7d569 --- /dev/null +++ b/tests/goldens/compiler/failure/config-watermark-limit-below-lookback.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': max_microbatches 2 is below the ordinary lookback requirement of 4 batches" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/constant-header-nested-too-deep.json b/tests/goldens/compiler/failure/constant-header-nested-too-deep.json new file mode 100644 index 0000000000..766c4e1b73 --- /dev/null +++ b/tests/goldens/compiler/failure/constant-header-nested-too-deep.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "CONSTANT(...) in '/models/staging/_sqlbuild/_constants/statuses.sql:1' contains invalid SQLBuild header syntax: values nest deeper than 256 levels", + "help": "flatten the value so it nests at most 256 levels deep" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/context-variable-in-model-sql.json b/tests/goldens/compiler/failure/context-variable-in-model-sql.json new file mode 100644 index 0000000000..7f1b08f4cf --- /dev/null +++ b/tests/goldens/compiler/failure/context-variable-in-model-sql.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL text in '/models/staging/stg_orders.sql' does not allow @@CTX templates" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/contract-dynamic-columns-unproven.json b/tests/goldens/compiler/failure/contract-dynamic-columns-unproven.json new file mode 100644 index 0000000000..fc9632ced7 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-dynamic-columns-unproven.json @@ -0,0 +1,289 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'customer_totals' dynamic column contract is not proven: dynamic pivot input does not have an authoritative, explicit schema", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "help": "project one supported runtime-dynamic pivot through a wildcard output boundary and declare every generated family" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "PIVOT __ref(\"stg_orders\")", + "ON status", + "USING MAX(amount)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-dynamic-columns-unsupported-dialect.json b/tests/goldens/compiler/failure/contract-dynamic-columns-unsupported-dialect.json new file mode 100644 index 0000000000..2d8a604087 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-dynamic-columns-unsupported-dialect.json @@ -0,0 +1,288 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'customer_totals' dynamic column contract is not proven: adapter dialect 'postgresql' does not support compiler-proven dynamic pivots", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "help": "project one supported runtime-dynamic pivot through a wildcard output boundary and declare every generated family" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, MAX(amount) AS placed", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "public", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "public.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "public", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "public.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-dynamic-family-type-mismatch.json b/tests/goldens/compiler/failure/contract-dynamic-family-type-mismatch.json new file mode 100644 index 0000000000..fda60c4471 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-dynamic-family-type-mismatch.json @@ -0,0 +1,328 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "dynamic column family 'status_amounts' inferred as DOUBLE but declared type is VARCHAR", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "help": "correct the family type or the pivot aggregate input type" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "PIVOT __ref(\"stg_orders\")", + "ON status", + "USING MAX(amount)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT CAST(order_id AS INTEGER) AS order_id,", + " CAST(customer_id AS INTEGER) AS customer_id,", + " CAST(amount AS DOUBLE) AS amount, CAST(status AS VARCHAR) AS status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order amounts per status", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "VARCHAR", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-errors-across-models.json b/tests/goldens/compiler/failure/contract-errors-across-models.json new file mode 100644 index 0000000000..76a591bf7f --- /dev/null +++ b/tests/goldens/compiler/failure/contract-errors-across-models.json @@ -0,0 +1,380 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'total_amount' inferred as DOUBLE but declared type is BIGINT", + "resource_type": "model", + "resource_name": "typed_totals", + "column_name": "total_amount", + "path": "models/marts/typed_totals.sql", + "line": 3, + "column": 12, + "location": { + "path": "models/marts/typed_totals.sql", + "line": 3, + "column": 12, + "end_line": 3, + "end_column": 24 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/marts/typed_totals.sql", + "line": 6, + "column": 8, + "end_line": 6, + "end_column": 43 + }, + "message": "inferred DOUBLE" + } + ], + "help": "change the declared type or cast the expression explicitly" + }, + { + "phase": "contract", + "severity": "error", + "code": "K006", + "message": "model 'stg_orders' has contract enforced but declares no columns", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "help": "add MODEL(columns (...)), declare a proven MODEL(dynamic_columns (...)) family, or set contract none for this model" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, CAST(SUM(amount) AS VARCHAR) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/typed_totals.sql": [ + "SELECT CAST(1.5 AS DOUBLE) AS total_amount", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.typed_totals": { + "database": null, + "schema": "main", + "name": "typed_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/typed_totals.sql", + "original_file_path": "models/marts/typed_totals.sql", + "unique_id": "model.failure_corpus.typed_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "typed_totals" + ], + "alias": "typed_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Typed totals", + "columns": { + "total_amount": { + "name": "total_amount", + "description": "", + "meta": {}, + "data_type": "BIGINT", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.typed_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.typed_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-extra-column.json b/tests/goldens/compiler/failure/contract-extra-column.json new file mode 100644 index 0000000000..b67d98b5f4 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-extra-column.json @@ -0,0 +1,303 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K005", + "message": "column 'status' is not declared in enforced contract for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "status", + "path": "models/staging/stg_orders.sql", + "line": 11, + "column": 39, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 11, + "column": 39, + "end_line": 11, + "end_column": 45 + }, + "help": "add the column to MODEL(columns) or remove it from the SELECT list" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-immediate-promotion-several-models.json b/tests/goldens/compiler/failure/contract-immediate-promotion-several-models.json new file mode 100644 index 0000000000..c6fab88b86 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-immediate-promotion-several-models.json @@ -0,0 +1,321 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'customer_totals': contract enforced requires staged table promotion; immediate table promotion cannot validate runtime output before target mutation", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "help": "sqlbuild_project.toml sets [settings] table_promotion_mode = \"immediate\"; enforced contracts are validated in a staging table before promotion\n = help: remove that line to use the default staged promotion, or set this in sqlbuild_project.toml:\n [settings]\n table_promotion_mode = \"staged\"\n = help: or remove the model's enforced contract: `contract enforced` in its MODEL header, or `contract = \"enforced\"` in the [defaults] or [path_defaults] entry that applies to it" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "total_amount": { + "name": "total_amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-immediate-promotion.json b/tests/goldens/compiler/failure/contract-immediate-promotion.json new file mode 100644 index 0000000000..e6761a433d --- /dev/null +++ b/tests/goldens/compiler/failure/contract-immediate-promotion.json @@ -0,0 +1,302 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'stg_orders': contract enforced requires staged table promotion; immediate table promotion cannot validate runtime output before target mutation", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "help": "sqlbuild_project.toml sets [settings] table_promotion_mode = \"immediate\"; enforced contracts are validated in a staging table before promotion\n = help: remove that line to use the default staged promotion, or set this in sqlbuild_project.toml:\n [settings]\n table_promotion_mode = \"staged\"\n = help: or remove the model's enforced contract: `contract enforced` in its MODEL header, or `contract = \"enforced\"` in the [defaults] or [path_defaults] entry that applies to it" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-implicit-missing-column.json b/tests/goldens/compiler/failure/contract-implicit-missing-column.json new file mode 100644 index 0000000000..87a901d28f --- /dev/null +++ b/tests/goldens/compiler/failure/contract-implicit-missing-column.json @@ -0,0 +1,303 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K001", + "message": "declared column 'order_count' was not found in statically inferred output for model 'customer_totals'", + "resource_type": "model", + "resource_name": "customer_totals", + "column_name": "order_count", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 16 + }, + "help": "add order_count to the SELECT list or correct/remove MODEL(columns (...)); MODEL(columns (...)) is validated using static SQL analysis because settings.column_contract_mode is \"implicit\" (the default). If this project intentionally uses columns only for metadata and audits, set [settings] column_contract_mode = \"explicit\"; models with contract enforced remain validated" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "total_amount": { + "name": "total_amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "order_count": { + "name": "order_count", + "description": "", + "meta": {}, + "data_type": "BIGINT", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-local-immediate-promotion.json b/tests/goldens/compiler/failure/contract-local-immediate-promotion.json new file mode 100644 index 0000000000..ffbc3c59c3 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-local-immediate-promotion.json @@ -0,0 +1,302 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K011", + "message": "model 'stg_orders': contract enforced requires staged table promotion; immediate table promotion cannot validate runtime output before target mutation", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "help": "sqlbuild_local.toml sets [settings] table_promotion_mode = \"immediate\"; enforced contracts are validated in a staging table before promotion\n = help: remove that line to use the default staged promotion, or set this in sqlbuild_local.toml:\n [settings]\n table_promotion_mode = \"staged\"\n = help: or remove the model's enforced contract: `contract enforced` in its MODEL header, or `contract = \"enforced\"` in the [defaults] or [path_defaults] entry that applies to it" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-missing-column.json b/tests/goldens/compiler/failure/contract-missing-column.json new file mode 100644 index 0000000000..4569eb6cb6 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-missing-column.json @@ -0,0 +1,321 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K001", + "message": "enforced contract column 'discount' was not found in statically inferred output for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "discount", + "path": "models/staging/stg_orders.sql", + "line": 9, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 9, + "column": 5, + "end_line": 9, + "end_column": 13 + }, + "help": "add discount to the SELECT list or correct MODEL(columns (...)); validation is active because this model declares contract enforced" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "discount": { + "name": "discount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-named-schema-columns.json b/tests/goldens/compiler/failure/contract-named-schema-columns.json new file mode 100644 index 0000000000..6c70207613 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-named-schema-columns.json @@ -0,0 +1,332 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K005", + "message": "column 'status' is not declared in enforced contract for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "status", + "path": "models/staging/stg_orders.sql", + "line": 7, + "column": 39, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 7, + "column": 39, + "end_line": 7, + "end_column": 45 + }, + "help": "add the column to the named SCHEMA or remove it from the SELECT list" + }, + { + "phase": "contract", + "severity": "error", + "code": "K001", + "message": "enforced contract column 'shipped_at' was not found in statically inferred output for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "shipped_at", + "path": "models/staging/_sqlbuild/_schemas/staged_order.sql", + "line": 8, + "column": 5, + "location": { + "path": "models/staging/_sqlbuild/_schemas/staged_order.sql", + "line": 8, + "column": 5, + "end_line": 8, + "end_column": 15 + }, + "help": "add shipped_at to the SELECT list or correct the named SCHEMA declaration; validation is active because this model declares contract enforced" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "shipped_at": { + "name": "shipped_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-nullability.json b/tests/goldens/compiler/failure/contract-nullability.json new file mode 100644 index 0000000000..b76fd7bb4e --- /dev/null +++ b/tests/goldens/compiler/failure/contract-nullability.json @@ -0,0 +1,325 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K004", + "message": "column 'customer_id' is declared non-null but may be nullable", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "customer_id", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 16 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 18, + "end_line": 12, + "end_column": 54 + }, + "message": "output expression proven nullable" + } + ], + "help": "use COALESCE, filter nulls explicitly, or remove the non-null contract" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, CAST(NULL AS INTEGER) AS customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-order-every-column-family.json b/tests/goldens/compiler/failure/contract-order-every-column-family.json new file mode 100644 index 0000000000..8726fb269d --- /dev/null +++ b/tests/goldens/compiler/failure/contract-order-every-column-family.json @@ -0,0 +1,398 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K005", + "message": "column 'status' is not declared in enforced contract for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "status", + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 64, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 64, + "end_line": 12, + "end_column": 70 + }, + "help": "add the column to MODEL(columns) or remove it from the SELECT list" + }, + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'order_id' inferred as INTEGER but declared type is VARCHAR", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "order_id", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 13 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 8, + "end_line": 12, + "end_column": 16 + }, + "message": "inferred INTEGER" + } + ], + "help": "change the declared type or cast the expression explicitly" + }, + { + "phase": "contract", + "severity": "error", + "code": "K004", + "message": "column 'customer_id' is declared non-null but may be nullable", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "customer_id", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 16 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 18, + "end_line": 12, + "end_column": 54 + }, + "message": "output expression proven nullable" + } + ], + "help": "use COALESCE, filter nulls explicitly, or remove the non-null contract" + }, + { + "phase": "contract", + "severity": "error", + "code": "K001", + "message": "enforced contract column 'shipped_at' was not found in statically inferred output for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "shipped_at", + "path": "models/staging/stg_orders.sql", + "line": 7, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 7, + "column": 5, + "end_line": 7, + "end_column": 15 + }, + "help": "add shipped_at to the SELECT list or correct MODEL(columns (...)); validation is active because this model declares contract enforced" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, CAST(NULL AS INTEGER) AS customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "shipped_at": { + "name": "shipped_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-type-mismatch.json b/tests/goldens/compiler/failure/contract-type-mismatch.json new file mode 100644 index 0000000000..b02987306e --- /dev/null +++ b/tests/goldens/compiler/failure/contract-type-mismatch.json @@ -0,0 +1,325 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'order_id' inferred as INTEGER but declared type is VARCHAR", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "order_id", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 5, + "end_line": 5, + "end_column": 13 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 8, + "end_line": 12, + "end_column": 16 + }, + "message": "inferred INTEGER" + } + ], + "help": "change the declared type or cast the expression explicitly" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-unknown-type.json b/tests/goldens/compiler/failure/contract-unknown-type.json new file mode 100644 index 0000000000..c0d4f7a6f1 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-unknown-type.json @@ -0,0 +1,298 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K002", + "message": "column 'order_id' inferred as INTEGER but declared type is MYSTERY_TYPE", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "order_id", + "path": "models/staging/stg_orders.sql", + "line": 4, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 4, + "column": 5, + "end_line": 4, + "end_column": 13 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 8, + "column": 8, + "end_line": 8, + "end_column": 16 + }, + "message": "inferred INTEGER" + } + ], + "help": "change the declared type or cast the expression explicitly" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "MYSTERY_TYPE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/contract-without-columns.json b/tests/goldens/compiler/failure/contract-without-columns.json new file mode 100644 index 0000000000..480749a518 --- /dev/null +++ b/tests/goldens/compiler/failure/contract-without-columns.json @@ -0,0 +1,265 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K006", + "message": "model 'stg_orders' has contract enforced but declares no columns", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "help": "add MODEL(columns (...)), declare a proven MODEL(dynamic_columns (...)) family, or set contract none for this model" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/cursor-intrinsic-outside-incremental.json b/tests/goldens/compiler/failure/cursor-intrinsic-outside-incremental.json new file mode 100644 index 0000000000..38b924499f --- /dev/null +++ b/tests/goldens/compiler/failure/cursor-intrinsic-outside-incremental.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model 'stg_orders' uses cursor intrinsics but is not a built-in incremental model" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/cursor-model-without-inputs.json b/tests/goldens/compiler/failure/cursor-model-without-inputs.json new file mode 100644 index 0000000000..8fed1f1c08 --- /dev/null +++ b/tests/goldens/compiler/failure/cursor-model-without-inputs.json @@ -0,0 +1,268 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P011", + "message": "incremental model 'customer_totals' reads no inputs, so builds after the first cannot work out their cursor window", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 3, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 3, + "end_line": 5, + "end_column": 19 + }, + "help": "read the data through __ref(), __source() or __seed() so its cursor can bound the window, or use materialized table if the model has no upstream data" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT TIMESTAMP '2026-01-01 00:00:00' AS placed_at, 1 AS customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/cursor-unknown-column.json b/tests/goldens/compiler/failure/cursor-unknown-column.json new file mode 100644 index 0000000000..f614aa5ce4 --- /dev/null +++ b/tests/goldens/compiler/failure/cursor-unknown-column.json @@ -0,0 +1,272 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "cursor references unknown column 'placed_at'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 10, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 10 + }, + "help": "change the metadata column name to an existing output column" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/dbt-reference-without-manifest.json b/tests/goldens/compiler/failure/dbt-reference-without-manifest.json new file mode 100644 index 0000000000..6f3b715373 --- /dev/null +++ b/tests/goldens/compiler/failure/dbt-reference-without-manifest.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/marts/customer_totals.sql uses __dbt_ref(\"upstream_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/dbt-unknown-key.json b/tests/goldens/compiler/failure/dbt-unknown-key.json new file mode 100644 index 0000000000..349baa71af --- /dev/null +++ b/tests/goldens/compiler/failure/dbt-unknown-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_project.toml dbt contains unknown key(s): manifest. Allowed keys: profiles_dir, project_dir, target, target_path, vars", + "help": "supported keys: profiles_dir, project_dir, target, target_path, vars" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-first-of-two-reference-errors.json b/tests/goldens/compiler/failure/declaration-first-of-two-reference-errors.json new file mode 100644 index 0000000000..a2c4b904e1 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-first-of-two-reference-errors.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown member 'HELD' for enum 'staged_status' in '/models/staging/stg_orders.sql'. Available members: PLACED" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-group-below-root.json b/tests/goldens/compiler/failure/declaration-group-below-root.json new file mode 100644 index 0000000000..ebbb8b534f --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-group-below-root.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Grouped declaration root models/_sqlbuild/ must be below a concrete owner directory; use the project-wide macros/, enums/, constants/, audits/, schemas/, or hooks/ root instead" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-group-unsupported-entry.json b/tests/goldens/compiler/failure/declaration-group-unsupported-entry.json new file mode 100644 index 0000000000..71f4684d71 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-group-unsupported-entry.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Declaration group models/marts/_sqlbuild/ contains unsupported entries: models/marts/_sqlbuild/notes.txt" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-inaccessible-local-constant.json b/tests/goldens/compiler/failure/declaration-inaccessible-local-constant.json new file mode 100644 index 0000000000..32d7405555 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-inaccessible-local-constant.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Constant 'order_cap' is known but inaccessible in '/models/staging/stg_orders.sql'. It is defined at models/marts/_constants/limits.sql:1:1 with local scope owned by 'models/marts'; consumer path: '/models/staging/stg_orders.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-invalid-constant-reference.json b/tests/goldens/compiler/failure/declaration-invalid-constant-reference.json new file mode 100644 index 0000000000..407aef0a1a --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-invalid-constant-reference.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Invalid constant reference in '/models/staging/stg_orders.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-root-nested.json b/tests/goldens/compiler/failure/declaration-root-nested.json new file mode 100644 index 0000000000..1a803d6726 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-root-nested.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Declaration root models/marts/_enums/_constants/ is nested inside another declaration tree" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-unclosed-quote-before-reference.json b/tests/goldens/compiler/failure/declaration-unclosed-quote-before-reference.json new file mode 100644 index 0000000000..df2f8f4d34 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-unclosed-quote-before-reference.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Enum and constant expansion contains an unclosed quoted string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/declaration-unknown-enum-after-macro.json b/tests/goldens/compiler/failure/declaration-unknown-enum-after-macro.json new file mode 100644 index 0000000000..3e9904a035 --- /dev/null +++ b/tests/goldens/compiler/failure/declaration-unknown-enum-after-macro.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown enum 'missing_status' in '/models/staging/stg_orders.sql'. Visible enums: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-declaration.json b/tests/goldens/compiler/failure/duplicate-declaration.json new file mode 100644 index 0000000000..bbf984bf10 --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-declaration.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Invalid declaration scope index:\n[S003] Duplicate declaration 'constant:minimum_amount' at models/staging/_sqlbuild/_constants/limits.sql:1:1, models/staging/_sqlbuild/_constants/limits.sql:1:1\n[S003] Duplicate declaration 'constant:minimum_amount' at models/staging/_sqlbuild/_constants/limits.sql:1:1, models/staging/_sqlbuild/_constants/limits.sql:1:1" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-hook.json b/tests/goldens/compiler/failure/duplicate-hook.json new file mode 100644 index 0000000000..2a11772cb4 --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-hook.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D011", + "message": "Duplicate hook name 'note_refresh' found in hooks/python/first.py and hooks/python/second.py" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-model.json b/tests/goldens/compiler/failure/duplicate-model.json new file mode 100644 index 0000000000..b9b49b0472 --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-model.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Duplicate model file name found for 'stg_orders' in models/marts/stg_orders.sql and models/staging/stg_orders.sql" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-provider.json b/tests/goldens/compiler/failure/duplicate-provider.json new file mode 100644 index 0000000000..2c25af46db --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-provider.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D012", + "message": "Duplicate provider name 'export_settings' found in providers/first.py and providers/second.py" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-python-node.json b/tests/goldens/compiler/failure/duplicate-python-node.json new file mode 100644 index 0000000000..7b8d648d20 --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-python-node.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Duplicate Python node found for 'export_orders' in python/tasks/first.py and python/tasks/second.py; loader, task, asset, and check names must be globally unique" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-scenario.json b/tests/goldens/compiler/failure/duplicate-scenario.json new file mode 100644 index 0000000000..1436b1b6b4 --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-scenario.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Duplicate scenario file name found for 'orders' in tests/scenarios/north/orders.sql and tests/scenarios/south/orders.sql" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/duplicate-source.json b/tests/goldens/compiler/failure/duplicate-source.json new file mode 100644 index 0000000000..1b824c951e --- /dev/null +++ b/tests/goldens/compiler/failure/duplicate-source.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Duplicate source declaration found for 'raw_orders' in sources/more.yml and sources/raw.yml" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/engine-error-case-folded-duplicate-column.json b/tests/goldens/compiler/failure/engine-error-case-folded-duplicate-column.json new file mode 100644 index 0000000000..8595e5f723 --- /dev/null +++ b/tests/goldens/compiler/failure/engine-error-case-folded-duplicate-column.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/marts/customer_totals.sql model has duplicate column 'größe' (column names are case-insensitive)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/engine-error-unset-environment-variable.json b/tests/goldens/compiler/failure/engine-error-unset-environment-variable.json new file mode 100644 index 0000000000..d34e094776 --- /dev/null +++ b/tests/goldens/compiler/failure/engine-error-unset-environment-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown environment variable '@@ENV:SQB_ENGINE_ERROR_UNSET_REGION' in '/models/marts/customer_totals.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/engine-error-week-date-cursor-start.json b/tests/goldens/compiler/failure/engine-error-week-date-cursor-start.json new file mode 100644 index 0000000000..c835739003 --- /dev/null +++ b/tests/goldens/compiler/failure/engine-error-week-date-cursor-start.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'customer_totals': cursor_start value '2024-W01-1T25:00' is not a valid ISO timestamp: hour must be in 0..23" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/enum-duplicate-member.json b/tests/goldens/compiler/failure/enum-duplicate-member.json new file mode 100644 index 0000000000..aea3a7ecad --- /dev/null +++ b/tests/goldens/compiler/failure/enum-duplicate-member.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "/models/staging/_sqlbuild/_enums/order_status.sql enum 'order_status' has duplicate member 'PLACED'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/enum-parse.json b/tests/goldens/compiler/failure/enum-parse.json new file mode 100644 index 0000000000..57406a204d --- /dev/null +++ b/tests/goldens/compiler/failure/enum-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "ENUM(...) in '/enums/order_status.sql' contains invalid SQLBuild header syntax: expected value at position 35" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/failing-macro.json b/tests/goldens/compiler/failure/failing-macro.json new file mode 100644 index 0000000000..f8ffc4fae3 --- /dev/null +++ b/tests/goldens/compiler/failure/failing-macro.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@cents' in '/models/staging/stg_orders.sql' failed: cannot convert amount" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/generic-audit-cursor-intrinsic.json b/tests/goldens/compiler/failure/generic-audit-cursor-intrinsic.json new file mode 100644 index 0000000000..139a76c54e --- /dev/null +++ b/tests/goldens/compiler/failure/generic-audit-cursor-intrinsic.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Audit 'fresh' uses cursor intrinsics, which are only supported in cursor-based incremental model query SQL" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/generic-audit-header.json b/tests/goldens/compiler/failure/generic-audit-header.json new file mode 100644 index 0000000000..3bbb5d34fa --- /dev/null +++ b/tests/goldens/compiler/failure/generic-audit-header.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D004", + "message": "AUDIT() in '/models/marts/_sqlbuild/_audits/generic/at_least.sql:1' has unsupported keys: unknown_option", + "help": "supported keys: always_run, evaluation, minimum_samples, name, run_scope, sample_count, sample_unit, severity, sql_analysis, thresholds, value" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/generic-audit-missing-argument.json b/tests/goldens/compiler/failure/generic-audit-missing-argument.json new file mode 100644 index 0000000000..5e02dc2c5e --- /dev/null +++ b/tests/goldens/compiler/failure/generic-audit-missing-argument.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql is missing argument 'minimum' for generic audit 'floor'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/generic-audit-overrides-implicit-model.json b/tests/goldens/compiler/failure/generic-audit-overrides-implicit-model.json new file mode 100644 index 0000000000..31faebe172 --- /dev/null +++ b/tests/goldens/compiler/failure/generic-audit-overrides-implicit-model.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql audit 'floor' must not override implicit model from attached context" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/generic-audit-unknown-run-scope.json b/tests/goldens/compiler/failure/generic-audit-unknown-run-scope.json new file mode 100644 index 0000000000..f138d91f5f --- /dev/null +++ b/tests/goldens/compiler/failure/generic-audit-unknown-run-scope.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown audit run_scope 'always'; valid values: delta_and_final, final" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/hard-coded-relation-in-python.json b/tests/goldens/compiler/failure/hard-coded-relation-in-python.json new file mode 100644 index 0000000000..6002c32dfd --- /dev/null +++ b/tests/goldens/compiler/failure/hard-coded-relation-in-python.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P008", + "message": "task:export_orders names model:stg_orders as 'stg_orders' in SQL passed to ctx.query()", + "path": "python/tasks/exports.py", + "line": 7, + "column": 1, + "location": { + "path": "python/tasks/exports.py", + "line": 7, + "column": 1 + }, + "help": "declare it with depends_on=model(\"stg_orders\") and use ctx.relation(model(\"stg_orders\")) instead of the relation name\n = help: if 'stg_orders' is an external table that shares the name, qualify it with its schema\n = help: the current value is [references] enforce_explicit = true (from sqlbuild_project.toml or its default); while migrating a project, to allow hard-coded relation names, set this in sqlbuild_project.toml:\n [references]\n enforce_explicit = false" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/header-audit-identity.json b/tests/goldens/compiler/failure/header-audit-identity.json new file mode 100644 index 0000000000..90bd441865 --- /dev/null +++ b/tests/goldens/compiler/failure/header-audit-identity.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Invalid model audit definition identity 'NotNull' in models/staging/stg_orders.sql; use snake_case 'not_null'", + "help": "Rename the authored identity and update its references, selectors, and integration keys. SQLBuild does not silently normalize resource identities. Double underscores remain valid." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/header-audit-severity.json b/tests/goldens/compiler/failure/header-audit-severity.json new file mode 100644 index 0000000000..c4c39c8630 --- /dev/null +++ b/tests/goldens/compiler/failure/header-audit-severity.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model audit 'unique_combination' 'severity' must be one of: warn, error" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/header-column-audits-not-a-list.json b/tests/goldens/compiler/failure/header-column-audits-not-a-list.json new file mode 100644 index 0000000000..411e67da84 --- /dev/null +++ b/tests/goldens/compiler/failure/header-column-audits-not-a-list.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model column 'order_id' audits must be a list" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/header-column-type-not-text.json b/tests/goldens/compiler/failure/header-column-type-not-text.json new file mode 100644 index 0000000000..f3b20117b1 --- /dev/null +++ b/tests/goldens/compiler/failure/header-column-type-not-text.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model column 'order_id' 'type' must be a non-empty string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/header-column-unknown-metadata-key.json b/tests/goldens/compiler/failure/header-column-unknown-metadata-key.json new file mode 100644 index 0000000000..26fd68c93b --- /dev/null +++ b/tests/goldens/compiler/failure/header-column-unknown-metadata-key.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model column 'order_id' has unknown metadata keys: format" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/header-duplicate-column.json b/tests/goldens/compiler/failure/header-duplicate-column.json new file mode 100644 index 0000000000..33959188fb --- /dev/null +++ b/tests/goldens/compiler/failure/header-duplicate-column.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model has duplicate column 'ORDER_ID' (column names are case-insensitive)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/hook-reads-dependant.json b/tests/goldens/compiler/failure/hook-reads-dependant.json new file mode 100644 index 0000000000..58c2f1bc67 --- /dev/null +++ b/tests/goldens/compiler/failure/hook-reads-dependant.json @@ -0,0 +1,280 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P007", + "message": "Python hook 'note_refresh' on model 'stg_orders' reads model 'customer_totals', which depends on 'stg_orders'; a hook runs as part of its model, so it cannot wait for a resource built from that model", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/_sqlbuild/_hooks/python/notes.py", + "help": "attach the hook to a model built after 'customer_totals', or drop the read and use ctx.destination for 'stg_orders' itself" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "python", + "name": "note_refresh", + "kwargs": {}, + "relative_path": "models/staging/_sqlbuild/_hooks/python/notes.py", + "definition_hash": "5d9bbe39d4017828edf4fac4743dc8253cd0f9b3d65779e5f9cff6100bee89dd", + "version_hash": "38cb2db363acaa4f13ad2ac96e920b672895acf529c55e86c75d1ab2c73137a9" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/hook-role-unsupported-entry.json b/tests/goldens/compiler/failure/hook-role-unsupported-entry.json new file mode 100644 index 0000000000..c9109a0c9a --- /dev/null +++ b/tests/goldens/compiler/failure/hook-role-unsupported-entry.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Unsupported entries in models/marts/_sqlbuild/hooks/: models/marts/_sqlbuild/hooks/notes.sql; hooks/ accepts only python/, sql/" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/hook-unknown-argument.json b/tests/goldens/compiler/failure/hook-unknown-argument.json new file mode 100644 index 0000000000..accbb62629 --- /dev/null +++ b/tests/goldens/compiler/failure/hook-unknown-argument.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "/models/marts/customer_totals.sql post_hooks[0] sql(\"record_refresh\") passes unknown argument(s) to SQL hook 'record_refresh' in hooks/sql/record_refresh.sql: tag" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/hook-without-header.json b/tests/goldens/compiler/failure/hook-without-header.json new file mode 100644 index 0000000000..0ab3158d7b --- /dev/null +++ b/tests/goldens/compiler/failure/hook-without-header.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D014", + "message": "SQL hook '/hooks/sql/record_refresh.sql' must start with a HOOK() header as the first non-whitespace content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/inaccessible-declaration.json b/tests/goldens/compiler/failure/inaccessible-declaration.json new file mode 100644 index 0000000000..905dddc45a --- /dev/null +++ b/tests/goldens/compiler/failure/inaccessible-declaration.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Constant 'minimum_amount' is known but inaccessible in '/models/staging/stg_orders.sql'. It is defined at models/marts/_sqlbuild/_constants/limits.sql:1:1 with local scope owned by 'models/marts'; consumer path: '/models/staging/stg_orders.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/inherited-declaration-used-in-one-folder.json b/tests/goldens/compiler/failure/inherited-declaration-used-in-one-folder.json new file mode 100644 index 0000000000..45086430ab --- /dev/null +++ b/tests/goldens/compiler/failure/inherited-declaration-used-in-one-folder.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S008", + "message": "Declaration 'constant:minimum_amount' is currently descendant-public at 'models/staging' (models/staging/_sqlbuild/constants/limits.sql); required exact-owner-private at 'models/staging'. Consumers: model:stg_orders. Move it to 'models/staging/_sqlbuild/_constants/'", + "path": "models/staging/_sqlbuild/constants/limits.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/_sqlbuild/constants/limits.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "WHERE amount > 1", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/invalid-decimal-constant.json b/tests/goldens/compiler/failure/invalid-decimal-constant.json new file mode 100644 index 0000000000..a1488abd9f --- /dev/null +++ b/tests/goldens/compiler/failure/invalid-decimal-constant.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "/models/staging/_sqlbuild/_constants/limits.sql constant 'minimum_amount' has invalid decimal value 'ten'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/invalid-declaration-name.json b/tests/goldens/compiler/failure/invalid-declaration-name.json new file mode 100644 index 0000000000..74a1835434 --- /dev/null +++ b/tests/goldens/compiler/failure/invalid-declaration-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Invalid public constant identity 'MinimumAmount' in /models/staging/_sqlbuild/_constants/limits.sql; use snake_case 'minimum_amount'", + "help": "Rename the authored identity and update its references, selectors, and integration keys. SQLBuild does not silently normalize resource identities. Double underscores remain valid." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/invalid-reference-calls-in-two-files.json b/tests/goldens/compiler/failure/invalid-reference-calls-in-two-files.json new file mode 100644 index 0000000000..021ff54895 --- /dev/null +++ b/tests/goldens/compiler/failure/invalid-reference-calls-in-two-files.json @@ -0,0 +1,285 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(stg_orders) is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 23 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"stg_orders\")" + }, + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__source('raw_orders') is not a valid __source() call", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 28 + }, + "help": "__source() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __source(\"raw_orders\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(stg_orders)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source('raw_orders')", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/invalid-resource-name.json b/tests/goldens/compiler/failure/invalid-resource-name.json new file mode 100644 index 0000000000..33c6c184a5 --- /dev/null +++ b/tests/goldens/compiler/failure/invalid-resource-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Invalid model identity 'order-totals' in models/marts/order-totals.sql; use snake_case 'order_totals'", + "help": "Rename the authored identity and update its references, selectors, and integration keys. SQLBuild does not silently normalize resource identities. Double underscores remain valid." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/legacy-event-exporters-directory.json b/tests/goldens/compiler/failure/legacy-event-exporters-directory.json new file mode 100644 index 0000000000..2c0a87d690 --- /dev/null +++ b/tests/goldens/compiler/failure/legacy-event-exporters-directory.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D015", + "message": "event_exporters/ was replaced by sinks/ and @lifecycle_event_sink" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/lifecycle-sink-default-parameter.json b/tests/goldens/compiler/failure/lifecycle-sink-default-parameter.json new file mode 100644 index 0000000000..04787f8f41 --- /dev/null +++ b/tests/goldens/compiler/failure/lifecycle-sink-default-parameter.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D015", + "message": "Event exporter 'ignore_events' in sinks/lifecycle.py parameters must not have defaults" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/lifecycle-sink-unknown-provider.json b/tests/goldens/compiler/failure/lifecycle-sink-unknown-provider.json new file mode 100644 index 0000000000..e1b706e978 --- /dev/null +++ b/tests/goldens/compiler/failure/lifecycle-sink-unknown-provider.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D015", + "message": "Event exporter 'publish_events' in sinks/lifecycle.py requires unknown provider 'destination_client'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/lineage-opted-out-except-and-ctes.json b/tests/goldens/compiler/failure/lineage-opted-out-except-and-ctes.json new file mode 100644 index 0000000000..0e07d34bb1 --- /dev/null +++ b/tests/goldens/compiler/failure/lineage-opted-out-except-and-ctes.json @@ -0,0 +1,353 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B004", + "message": "Unknown table or alias 'x' referenced by column 'order_id'", + "resource_type": "model", + "resource_name": "broken_orders", + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 9 + }, + "help": "give each referenced relation a visible alias in this scope" + } + ] + } + ], + "compiled": { + "models/marts/broken_orders.sql": [ + "SELECT x.order_id", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/marts/customer_totals.sql": [ + "WITH kept AS (SELECT customer_id FROM __ref(\"stg_orders\")),", + "again AS (SELECT * FROM kept)", + "SELECT customer_id, COUNT(*) AS total_amount FROM again GROUP BY 1", + "EXCEPT", + "SELECT customer_id, amount FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.broken_orders": { + "database": null, + "schema": "main", + "name": "broken_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/broken_orders.sql", + "original_file_path": "models/marts/broken_orders.sql", + "unique_id": "model.failure_corpus.broken_orders", + "fqn": [ + "failure_corpus", + "models", + "marts", + "broken_orders" + ], + "alias": "broken_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Orders with an unknown qualifier", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.broken_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.broken_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/lineage-opted-out-quoted-columns.json b/tests/goldens/compiler/failure/lineage-opted-out-quoted-columns.json new file mode 100644 index 0000000000..708c091054 --- /dev/null +++ b/tests/goldens/compiler/failure/lineage-opted-out-quoted-columns.json @@ -0,0 +1,352 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B004", + "message": "Unknown table or alias 'x' referenced by column 'order_id'", + "resource_type": "model", + "resource_name": "broken_orders", + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 9 + }, + "help": "give each referenced relation a visible alias in this scope" + } + ] + } + ], + "compiled": { + "models/marts/broken_orders.sql": [ + "SELECT x.order_id", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT \"Customer_ID\", SUM(O.Amount) AS \"Total_Amount\",", + " CAST(MAX(o.status) AS VARCHAR) AS last_status, 'fixed' AS label", + "FROM __ref(\"stg_orders\") AS O", + "GROUP BY 1", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.broken_orders": { + "database": null, + "schema": "main", + "name": "broken_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/broken_orders.sql", + "original_file_path": "models/marts/broken_orders.sql", + "unique_id": "model.failure_corpus.broken_orders", + "fqn": [ + "failure_corpus", + "models", + "marts", + "broken_orders" + ], + "alias": "broken_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Orders with an unknown qualifier", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.broken_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.broken_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/lineage-opted-out-star.json b/tests/goldens/compiler/failure/lineage-opted-out-star.json new file mode 100644 index 0000000000..0d8db9c495 --- /dev/null +++ b/tests/goldens/compiler/failure/lineage-opted-out-star.json @@ -0,0 +1,350 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B004", + "message": "Unknown table or alias 'x' referenced by column 'order_id'", + "resource_type": "model", + "resource_name": "broken_orders", + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 9 + }, + "help": "give each referenced relation a visible alias in this scope" + } + ] + } + ], + "compiled": { + "models/marts/broken_orders.sql": [ + "SELECT x.order_id", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT o.order_id AS first_order, o.*", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.broken_orders": { + "database": null, + "schema": "main", + "name": "broken_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/broken_orders.sql", + "original_file_path": "models/marts/broken_orders.sql", + "unique_id": "model.failure_corpus.broken_orders", + "fqn": [ + "failure_corpus", + "models", + "marts", + "broken_orders" + ], + "alias": "broken_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Orders with an unknown qualifier", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.broken_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.broken_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/lineage-opted-out-union-of-stars.json b/tests/goldens/compiler/failure/lineage-opted-out-union-of-stars.json new file mode 100644 index 0000000000..854fbc877f --- /dev/null +++ b/tests/goldens/compiler/failure/lineage-opted-out-union-of-stars.json @@ -0,0 +1,354 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B004", + "message": "Unknown table or alias 'x' referenced by column 'order_id'", + "resource_type": "model", + "resource_name": "broken_orders", + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "location": { + "path": "models/marts/broken_orders.sql", + "line": 5, + "column": 8, + "end_line": 5, + "end_column": 9 + }, + "help": "give each referenced relation a visible alias in this scope" + } + ] + } + ], + "compiled": { + "models/marts/broken_orders.sql": [ + "SELECT x.order_id", + "FROM __ref(\"stg_orders\") o", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT *, 1 AS copy_number", + "FROM __ref(\"stg_orders\")", + "UNION ALL", + "SELECT \"R\".*, 2 FROM __source(\"raw_orders\") AS \"R\" JOIN __ref(\"stg_orders\") s ON TRUE", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.broken_orders": { + "database": null, + "schema": "main", + "name": "broken_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/broken_orders.sql", + "original_file_path": "models/marts/broken_orders.sql", + "unique_id": "model.failure_corpus.broken_orders", + "fqn": [ + "failure_corpus", + "models", + "marts", + "broken_orders" + ], + "alias": "broken_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Orders with an unknown qualifier", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.broken_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders", + "source.failure_corpus.raw_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.broken_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders", + "source.failure_corpus.raw_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/list-constant-mixed-types.json b/tests/goldens/compiler/failure/list-constant-mixed-types.json new file mode 100644 index 0000000000..e1ef440e76 --- /dev/null +++ b/tests/goldens/compiler/failure/list-constant-mixed-types.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "/models/staging/_sqlbuild/_constants/statuses.sql constant 'kept_statuses'[1] has type integer; expected string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/local-config-unknown-key.json b/tests/goldens/compiler/failure/local-config-unknown-key.json new file mode 100644 index 0000000000..82ca337180 --- /dev/null +++ b/tests/goldens/compiler/failure/local-config-unknown-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_local.toml settings contains unknown key(s): sql_analysiss. Allowed keys: auto_load_sources, column_contract_mode, concurrency, default_audit_run_scope, default_audit_severity, max_concurrency, microbatch_concurrency, microbatch_unaccounted_partition_policy, query_change_tracking, require_sql_analysis, sql_analysis, sql_validation, table_promotion_mode", + "help": "did you mean 'sql_analysis'?" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/local-macro-needed-below-owner.json b/tests/goldens/compiler/failure/local-macro-needed-below-owner.json new file mode 100644 index 0000000000..5f0025f710 --- /dev/null +++ b/tests/goldens/compiler/failure/local-macro-needed-below-owner.json @@ -0,0 +1,412 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S007", + "message": "Declaration 'macro:cents' is currently exact-owner-private at 'models/staging' (models/staging/_sqlbuild/_macros/orders.py); required exact-owner-private at 'models/staging/regional'. Consumers: macro:wrapped. Move it to 'models/staging/regional/_sqlbuild/_macros/'", + "path": "models/staging/_sqlbuild/_macros/orders.py", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/_sqlbuild/_macros/orders.py", + "line": 1, + "column": 1 + } + }, + { + "phase": "compile", + "severity": "error", + "code": "S008", + "message": "Declaration 'macro:wrapped' is currently descendant-public at 'models/staging' (models/staging/_sqlbuild/macros/wrapping.py); required exact-owner-private at 'models/staging/regional'. Consumers: model:stg_regional_orders. Move it to 'models/staging/regional/_sqlbuild/_macros/'", + "path": "models/staging/_sqlbuild/macros/wrapping.py", + "line": 4, + "column": 1, + "location": { + "path": "models/staging/_sqlbuild/macros/wrapping.py", + "line": 4, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/regional/stg_regional_orders.sql": [ + "SELECT order_id, (amount * 100) AS amount_cents", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_regional_orders": { + "database": null, + "schema": "main", + "name": "stg_regional_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/regional/stg_regional_orders.sql", + "original_file_path": "models/staging/regional/stg_regional_orders.sql", + "unique_id": "model.failure_corpus.stg_regional_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "regional", + "stg_regional_orders" + ], + "alias": "stg_regional_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_regional_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.failure_corpus.cents": { + "name": "cents", + "resource_type": "macro", + "package_name": "failure_corpus", + "path": "models/staging/_sqlbuild/_macros/orders.py", + "original_file_path": "models/staging/_sqlbuild/_macros/orders.py", + "unique_id": "macro.failure_corpus.cents", + "macro_sql": "def cents(expression: str) -> str:\n \"\"\"Convert to cents.\"\"\"\n return f\"({expression} * 100)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.failure_corpus.wrapped": { + "name": "wrapped", + "resource_type": "macro", + "package_name": "failure_corpus", + "path": "models/staging/_sqlbuild/macros/wrapping.py", + "original_file_path": "models/staging/_sqlbuild/macros/wrapping.py", + "unique_id": "macro.failure_corpus.wrapped", + "macro_sql": "from models.staging._sqlbuild._macros.orders import cents\n\n\ndef wrapped(expression: str) -> str:\n \"\"\"Wrap cents.\"\"\"\n return cents(expression)\n", + "depends_on": { + "macros": [ + "macro.failure_corpus.cents" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_regional_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/local-singular-audit.json b/tests/goldens/compiler/failure/local-singular-audit.json new file mode 100644 index 0000000000..5e954f12ed --- /dev/null +++ b/tests/goldens/compiler/failure/local-singular-audit.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "models/marts/_sqlbuild/_audits/singular/ is invalid: singular audits are never used by name, so folder-only visibility has no meaning; use _sqlbuild/audits/singular/" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-arguments-do-not-parse.json b/tests/goldens/compiler/failure/macro-arguments-do-not-parse.json new file mode 100644 index 0000000000..76bd9e282b --- /dev/null +++ b/tests/goldens/compiler/failure/macro-arguments-do-not-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro arguments in '/models/staging/stg_orders.sql' could not be parsed: invalid syntax (, line 1)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-first-of-two-failing-models.json b/tests/goldens/compiler/failure/macro-first-of-two-failing-models.json new file mode 100644 index 0000000000..9a92d52682 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-first-of-two-failing-models.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@blow_up' in '/models/marts/customer_totals.sql' failed: cannot render total" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-generated-reference.json b/tests/goldens/compiler/failure/macro-generated-reference.json new file mode 100644 index 0000000000..f778bac568 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-generated-reference.json @@ -0,0 +1,290 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P006", + "message": "model:customer_totals depends on model:stg_orders through macro staged_orders()", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/_sqlbuild/_macros/orders.py", + "help": "write the reference in the model, or pass it in: @staged_orders(__ref(\"stg_orders\"))\n = help: the current value is [references] enforce_explicit = true (from sqlbuild_project.toml or its default); while migrating a project, to allow macro-generated references, set this in sqlbuild_project.toml:\n [references]\n enforce_explicit = false" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.failure_corpus.staged_orders": { + "name": "staged_orders", + "resource_type": "macro", + "package_name": "failure_corpus", + "path": "models/marts/_sqlbuild/_macros/orders.py", + "original_file_path": "models/marts/_sqlbuild/_macros/orders.py", + "unique_id": "macro.failure_corpus.staged_orders", + "macro_sql": "def staged_orders() -> str:\n \"\"\"Return the staged orders relation.\"\"\"\n return '__ref(\"stg_orders\")'\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/macro-import-cycle.json b/tests/goldens/compiler/failure/macro-import-cycle.json new file mode 100644 index 0000000000..9eebdc8491 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-import-cycle.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro import cycle in 'macros/first.py': macros.first -> macros.second -> macros.first" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-in-sibling-scope.json b/tests/goldens/compiler/failure/macro-in-sibling-scope.json new file mode 100644 index 0000000000..0865f3526a --- /dev/null +++ b/tests/goldens/compiler/failure/macro-in-sibling-scope.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@cents' in '/models/staging/stg_orders.sql' is inaccessible. Defined at 'models/marts/_sqlbuild/_macros/orders.py:1:1' with scope owner 'models/marts'; consumer/definition path is '/models/staging/stg_orders.sql'. Visible macros: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-non-literal-argument.json b/tests/goldens/compiler/failure/macro-non-literal-argument.json new file mode 100644 index 0000000000..c2bf929aa5 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-non-literal-argument.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro arguments in '/models/staging/stg_orders.sql' must use only Python literals, nested macro calls, and __ref(), __source(), or __seed() references" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-output-calls-macro.json b/tests/goldens/compiler/failure/macro-output-calls-macro.json new file mode 100644 index 0000000000..d12c7c95d7 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-output-calls-macro.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@wrapped' in '/models/staging/stg_orders.sql' returned SQLBuild call(s) @cents(). Macro output must be final SQL. Compose macros with ordinary Python imports and function calls instead; nested @macro() calls are supported only when explicitly authored in SQL" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-private-helper.json b/tests/goldens/compiler/failure/macro-private-helper.json new file mode 100644 index 0000000000..e8581dc32d --- /dev/null +++ b/tests/goldens/compiler/failure/macro-private-helper.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown macro '@_scaled' in '/models/staging/stg_orders.sql'. Available macros: cents" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-raises-after-a-call.json b/tests/goldens/compiler/failure/macro-raises-after-a-call.json new file mode 100644 index 0000000000..acab2b6871 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-raises-after-a-call.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@explode' in '/models/staging/stg_orders.sql' failed: cannot render status" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-returned-invalid-reference-call.json b/tests/goldens/compiler/failure/macro-returned-invalid-reference-call.json new file mode 100644 index 0000000000..fd55833526 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-returned-invalid-reference-call.json @@ -0,0 +1,295 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(stg_orders) is not a valid __ref() call, returned by macro staged_orders()", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/_sqlbuild/_macros/orders.py", + "line": 3, + "column": 13, + "location": { + "path": "models/marts/_sqlbuild/_macros/orders.py", + "line": 3, + "column": 13, + "end_line": 3, + "end_column": 30 + }, + "help": "write __ref(\"stg_orders\") in the model and pass it in: @staged_orders(__ref(\"stg_orders\"))\n = help: __ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"stg_orders\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(stg_orders)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.failure_corpus.staged_orders": { + "name": "staged_orders", + "resource_type": "macro", + "package_name": "failure_corpus", + "path": "models/marts/_sqlbuild/_macros/orders.py", + "original_file_path": "models/marts/_sqlbuild/_macros/orders.py", + "unique_id": "macro.failure_corpus.staged_orders", + "macro_sql": "def staged_orders() -> str:\n \"\"\"Return the staged orders relation.\"\"\"\n return '__ref(stg_orders)'\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/macro-returns-non-string.json b/tests/goldens/compiler/failure/macro-returns-non-string.json new file mode 100644 index 0000000000..4a74fb3132 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-returns-non-string.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@answer' in '/models/staging/stg_orders.sql' must return a SQL string when used directly in SQL" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-test-helper-calls-udf.json b/tests/goldens/compiler/failure/macro-test-helper-calls-udf.json new file mode 100644 index 0000000000..3468b46e88 --- /dev/null +++ b/tests/goldens/compiler/failure/macro-test-helper-calls-udf.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_cents.sql' mode 'macro' helper CTE 'labels' must not call udf; call reusable logic only in __macro_actual__" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/macro-test-helper-malformed-reference.json b/tests/goldens/compiler/failure/macro-test-helper-malformed-reference.json new file mode 100644 index 0000000000..07233323af --- /dev/null +++ b/tests/goldens/compiler/failure/macro-test-helper-malformed-reference.json @@ -0,0 +1,305 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__source(\"raw\", \"orders\") is not a valid __source() call", + "path": "tests/unit/test_cents.sql", + "line": 6, + "column": 33, + "location": { + "path": "tests/unit/test_cents.sql", + "line": 6, + "column": 33, + "end_line": 6, + "end_column": 58 + }, + "help": "__source() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __source(\"source_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ], + "tests/macro test_cents/test_cents.sql": [ + "WITH input_values AS (SELECT 5 AS amount),", + "sample_orders AS (SELECT * FROM __source(\"raw\", \"orders\")),", + "__actual__macro_test_cents AS (SELECT (amount * 100) AS cents FROM input_values),", + "__expected__macro_test_cents AS (SELECT 500 AS cents)", + "SELECT 0 AS step_index, 'macro test_cents' AS model_name, (SELECT COUNT(*) FROM __actual__macro_test_cents) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_test_cents) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_test_cents EXCEPT SELECT * FROM __expected__macro_test_cents) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_test_cents EXCEPT SELECT * FROM __actual__macro_test_cents) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.failure_corpus.cents": { + "name": "cents", + "resource_type": "macro", + "package_name": "failure_corpus", + "path": "tests/unit/_macros/orders.py", + "original_file_path": "tests/unit/_macros/orders.py", + "unique_id": "macro.failure_corpus.cents", + "macro_sql": "def cents(expression: str) -> str:\n \"\"\"Convert to cents.\"\"\"\n return f\"({expression} * 100)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/macro-test-quoted-cte-name.json b/tests/goldens/compiler/failure/macro-test-quoted-cte-name.json new file mode 100644 index 0000000000..c120d3ab4e --- /dev/null +++ b/tests/goldens/compiler/failure/macro-test-quoted-cte-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_stg_orders.sql' CTE name \"__macro_actual__\" must be an unquoted identifier of ASCII letters, digits and underscores\n --> tests/unit/test_stg_orders.sql:4:1", + "help": "rename the CTE, for example __macro_actual__; quoted CTE names and names with $ or non-ASCII characters are not supported" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/managed-source-without-loader.json b/tests/goldens/compiler/failure/managed-source-without-loader.json new file mode 100644 index 0000000000..470980d011 --- /dev/null +++ b/tests/goldens/compiler/failure/managed-source-without-loader.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Managed source 'loaded_products' in sources/raw.yml requires loader 'loaded_products'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/materialization-import-error.json b/tests/goldens/compiler/failure/materialization-import-error.json new file mode 100644 index 0000000000..c135e75ea8 --- /dev/null +++ b/tests/goldens/compiler/failure/materialization-import-error.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D011", + "message": "Failed to import materialization file materializations/copy_table.py: No module named 'missing_warehouse_client'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/missing-description.json b/tests/goldens/compiler/failure/missing-description.json new file mode 100644 index 0000000000..996e78aa3c --- /dev/null +++ b/tests/goldens/compiler/failure/missing-description.json @@ -0,0 +1,272 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P010", + "message": "model 'stg_orders' has no description", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1 + }, + "help": "to describe model 'stg_orders', add this to the MODEL header in models/staging/stg_orders.sql:\n MODEL (\n description \"What one row of stg_orders represents\",\n ...\n );" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/model-blank-column-type.json b/tests/goldens/compiler/failure/model-blank-column-type.json new file mode 100644 index 0000000000..bfb4d464a3 --- /dev/null +++ b/tests/goldens/compiler/failure/model-blank-column-type.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model column 'amount' 'type' must be a non-empty string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-bom.json b/tests/goldens/compiler/failure/model-bom.json new file mode 100644 index 0000000000..46c3a414d8 --- /dev/null +++ b/tests/goldens/compiler/failure/model-bom.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "SQL model '/models/staging/stg_orders.sql' must start with a MODEL(...) header as the first non-whitespace content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-column-audit-unknown-severity.json b/tests/goldens/compiler/failure/model-column-audit-unknown-severity.json new file mode 100644 index 0000000000..12389687b5 --- /dev/null +++ b/tests/goldens/compiler/failure/model-column-audit-unknown-severity.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model column 'amount' audit 'not_null' 'severity' must be one of: warn, error" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-duplicate-column.json b/tests/goldens/compiler/failure/model-duplicate-column.json new file mode 100644 index 0000000000..db3b188fff --- /dev/null +++ b/tests/goldens/compiler/failure/model-duplicate-column.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/staging/stg_orders.sql model has duplicate column 'AMOUNT' (column names are case-insensitive)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-header-nested-too-deep.json b/tests/goldens/compiler/failure/model-header-nested-too-deep.json new file mode 100644 index 0000000000..f0eb3e117e --- /dev/null +++ b/tests/goldens/compiler/failure/model-header-nested-too-deep.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "MODEL(...) in '/models/staging/stg_orders.sql:3' contains invalid SQLBuild header syntax: values nest deeper than 256 levels", + "help": "flatten the value so it nests at most 256 levels deep" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-header-syntax.json b/tests/goldens/compiler/failure/model-header-syntax.json new file mode 100644 index 0000000000..5d3b1f5aca --- /dev/null +++ b/tests/goldens/compiler/failure/model-header-syntax.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "MODEL(...) in '/models/staging/stg_orders.sql' contains invalid SQLBuild header syntax: expected key at position 50" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-missing-header.json b/tests/goldens/compiler/failure/model-missing-header.json new file mode 100644 index 0000000000..46c3a414d8 --- /dev/null +++ b/tests/goldens/compiler/failure/model-missing-header.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "SQL model '/models/staging/stg_orders.sql' must start with a MODEL(...) header as the first non-whitespace content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-nullable-column-with-not-null.json b/tests/goldens/compiler/failure/model-nullable-column-with-not-null.json new file mode 100644 index 0000000000..0c8e55f2d1 --- /dev/null +++ b/tests/goldens/compiler/failure/model-nullable-column-with-not-null.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P002", + "message": "models/staging/stg_orders.sql column 'amount' cannot set nullable = true and audit not_null", + "help": "remove the not_null audit or set nullable = false" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-path-not-utf8.json b/tests/goldens/compiler/failure/model-path-not-utf8.json new file mode 100644 index 0000000000..a04a655ed8 --- /dev/null +++ b/tests/goldens/compiler/failure/model-path-not-utf8.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Project path /models/staging/caf\\xe9.sql is not valid UTF-8; rename it so SQLBuild can read it" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-private-enum-misuse.json b/tests/goldens/compiler/failure/model-private-enum-misuse.json new file mode 100644 index 0000000000..e1cf0a0865 --- /dev/null +++ b/tests/goldens/compiler/failure/model-private-enum-misuse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown member 'PENDING' for enum '_state' in '/models/staging/stg_orders.sql'. Available members: OPEN, CLOSED" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-reserved-name.json b/tests/goldens/compiler/failure/model-reserved-name.json new file mode 100644 index 0000000000..d6fc87b3d8 --- /dev/null +++ b/tests/goldens/compiler/failure/model-reserved-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Invalid model identity '_chain_' in models/marts/_chain_.sql; use snake_case 'chain'", + "help": "Rename the authored identity and update its references, selectors, and integration keys. SQLBuild does not silently normalize resource identities. Double underscores remain valid." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-sql-syntax.json b/tests/goldens/compiler/failure/model-sql-syntax.json new file mode 100644 index 0000000000..d0fd5e25fc --- /dev/null +++ b/tests/goldens/compiler/failure/model-sql-syntax.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL syntax error in model 'stg_orders' (/models/staging/stg_orders.sql): Unexpected token: Comma", + "help": "if this SQL is valid for your warehouse, skip SQL analysis for this model, add this to the MODEL header:\n MODEL (\n sql_analysis false,\n ...\n );\n and please report the SQL so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-template-missing-environment.json b/tests/goldens/compiler/failure/model-template-missing-environment.json new file mode 100644 index 0000000000..73fb28ed55 --- /dev/null +++ b/tests/goldens/compiler/failure/model-template-missing-environment.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references missing ENV variable 'SQB_DIFFERENTIAL_UNSET'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-template-unknown-function.json b/tests/goldens/compiler/failure/model-template-unknown-function.json new file mode 100644 index 0000000000..598de35743 --- /dev/null +++ b/tests/goldens/compiler/failure/model-template-unknown-function.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model config references unsupported template function 'upper'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-template-unterminated-string.json b/tests/goldens/compiler/failure/model-template-unterminated-string.json new file mode 100644 index 0000000000..928b630a46 --- /dev/null +++ b/tests/goldens/compiler/failure/model-template-unterminated-string.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "template expression has unterminated single-quoted string at position 9" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/model-unknown-header-key.json b/tests/goldens/compiler/failure/model-unknown-header-key.json new file mode 100644 index 0000000000..a7f7d46ce2 --- /dev/null +++ b/tests/goldens/compiler/failure/model-unknown-header-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "MODEL() in '/models/staging/stg_orders.sql:3' has unsupported keys: materialised", + "help": "did you mean 'materialized'?" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/multiple-errors-order.json b/tests/goldens/compiler/failure/multiple-errors-order.json new file mode 100644 index 0000000000..a2e8ee113f --- /dev/null +++ b/tests/goldens/compiler/failure/multiple-errors-order.json @@ -0,0 +1,384 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P010", + "message": "model 'customer_totals' has no description", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 1, + "column": 1 + }, + "help": "to describe model 'customer_totals', add this to the MODEL header in models/marts/customer_totals.sql:\n MODEL (\n description \"What one row of customer_totals represents\",\n ...\n );" + }, + { + "phase": "compile", + "severity": "error", + "code": "P010", + "message": "model 'order_counts' has no description", + "resource_type": "model", + "resource_name": "order_counts", + "path": "models/marts/order_counts.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/marts/order_counts.sql", + "line": 1, + "column": 1 + }, + "help": "to describe model 'order_counts', add this to the MODEL header in models/marts/order_counts.sql:\n MODEL (\n description \"What one row of order_counts represents\",\n ...\n );" + }, + { + "phase": "compile", + "severity": "error", + "code": "P010", + "message": "model 'stg_orders' has no description", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1 + }, + "help": "to describe model 'stg_orders', add this to the MODEL header in models/staging/stg_orders.sql:\n MODEL (\n description \"What one row of stg_orders represents\",\n ...\n );" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/order_counts.sql": [ + "SELECT customer_id, COUNT(*) AS order_count", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.order_counts": { + "database": null, + "schema": "main", + "name": "order_counts", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/order_counts.sql", + "original_file_path": "models/marts/order_counts.sql", + "unique_id": "model.failure_corpus.order_counts", + "fqn": [ + "failure_corpus", + "models", + "marts", + "order_counts" + ], + "alias": "order_counts", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.order_counts", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.order_counts": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/named-hook-missing-argument.json b/tests/goldens/compiler/failure/named-hook-missing-argument.json new file mode 100644 index 0000000000..8d741b20ca --- /dev/null +++ b/tests/goldens/compiler/failure/named-hook-missing-argument.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "/models/marts/customer_totals.sql post_hooks[0] sql(\"record_refresh\") is missing argument 'label' for SQL hook 'record_refresh' in hooks/sql/record_refresh.sql" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/named-role-nested-declaration.json b/tests/goldens/compiler/failure/named-role-nested-declaration.json new file mode 100644 index 0000000000..6f8b5789cc --- /dev/null +++ b/tests/goldens/compiler/failure/named-role-nested-declaration.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Declaration directory schemas/enums/ is not allowed inside the project-wide schemas/ role; scoped declarations belong under /_sqlbuild/ below a resource tree" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/order-binding-metadata-contract.json b/tests/goldens/compiler/failure/order-binding-metadata-contract.json new file mode 100644 index 0000000000..c515f0891b --- /dev/null +++ b/tests/goldens/compiler/failure/order-binding-metadata-contract.json @@ -0,0 +1,361 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'refund' in stg_orders", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 25, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 25, + "end_line": 7, + "end_column": 31 + }, + "notes": [ + "stg_orders has: order_id, amount, discount, customer_id, status" + ] + }, + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "unique_key references unknown column 'order_key'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 15, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 4, + "column": 15 + }, + "help": "change the metadata column name to an existing output column" + }, + { + "phase": "contract", + "severity": "error", + "code": "K001", + "message": "enforced contract column 'discount' was not found in statically inferred output for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "discount", + "path": "models/staging/stg_orders.sql", + "line": 9, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 9, + "column": 5, + "end_line": 9, + "end_column": 13 + }, + "help": "add discount to the SELECT list or correct MODEL(columns (...)); validation is active because this model declares contract enforced" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(refund) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "order_key" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "discount": { + "name": "discount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/order-closest-column-help.json b/tests/goldens/compiler/failure/order-closest-column-help.json new file mode 100644 index 0000000000..e50e568592 --- /dev/null +++ b/tests/goldens/compiler/failure/order-closest-column-help.json @@ -0,0 +1,277 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'amonut' in stg_orders", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "end_line": 5, + "end_column": 31 + }, + "help": "did you mean 'amount'?", + "notes": [ + "stg_orders has: amount, status, customer_id, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amonut) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/order-contract-error-then-warning.json b/tests/goldens/compiler/failure/order-contract-error-then-warning.json new file mode 100644 index 0000000000..742801ce10 --- /dev/null +++ b/tests/goldens/compiler/failure/order-contract-error-then-warning.json @@ -0,0 +1,345 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "contract", + "severity": "error", + "code": "K005", + "message": "column 'status' is not declared in enforced contract for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "status", + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 53, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 53, + "end_line": 12, + "end_column": 59 + }, + "help": "add the column to MODEL(columns) or remove it from the SELECT list" + }, + { + "phase": "contract", + "severity": "warning", + "code": "K003", + "message": "column 'note' type could not be proven against declared VARCHAR", + "resource_type": "model", + "resource_name": "stg_orders", + "column_name": "note", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 5, + "end_line": 6, + "end_column": 9 + }, + "related_locations": [ + { + "label": "output", + "location": { + "path": "models/staging/stg_orders.sql", + "line": 12, + "column": 18, + "end_line": 12, + "end_column": 30 + }, + "message": "output expression with unproven type" + } + ], + "help": "add an explicit CAST if this declared type should be checked statically" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, NULL AS note, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "note": { + "name": "note", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/order-poisoned-downstream-uses.json b/tests/goldens/compiler/failure/order-poisoned-downstream-uses.json new file mode 100644 index 0000000000..631ed47dc9 --- /dev/null +++ b/tests/goldens/compiler/failure/order-poisoned-downstream-uses.json @@ -0,0 +1,277 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'refund' in raw_orders", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 39, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 39, + "end_line": 5, + "end_column": 45 + }, + "notes": [ + "raw_orders has: order_id, amount, customer_id, status", + "1 downstream output uses were not type-checked because of this error" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(refund) AS total_refund", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, refund, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/order-two-failing-models.json b/tests/goldens/compiler/failure/order-two-failing-models.json new file mode 100644 index 0000000000..c3bfef6368 --- /dev/null +++ b/tests/goldens/compiler/failure/order-two-failing-models.json @@ -0,0 +1,375 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'missing_column' in stg_orders", + "resource_type": "model", + "resource_name": "order_counts", + "path": "models/marts/order_counts.sql", + "line": 5, + "column": 27, + "location": { + "path": "models/marts/order_counts.sql", + "line": 5, + "column": 27, + "end_line": 5, + "end_column": 41 + }, + "notes": [ + "stg_orders has: discount, amount, status, customer_id, order_id" + ] + }, + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'discount' in raw_orders", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 39, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 39, + "end_line": 5, + "end_column": 47 + }, + "notes": [ + "raw_orders has: amount, customer_id, status, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/order_counts.sql": [ + "SELECT customer_id, COUNT(missing_column) AS order_count", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, discount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.order_counts": { + "database": null, + "schema": "main", + "name": "order_counts", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/order_counts.sql", + "original_file_path": "models/marts/order_counts.sql", + "unique_id": "model.failure_corpus.order_counts", + "fqn": [ + "failure_corpus", + "models", + "marts", + "order_counts" + ], + "alias": "order_counts", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order counts per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.order_counts", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.order_counts": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/orphan-audit-factory.json b/tests/goldens/compiler/failure/orphan-audit-factory.json new file mode 100644 index 0000000000..99894f52bb --- /dev/null +++ b/tests/goldens/compiler/failure/orphan-audit-factory.json @@ -0,0 +1,286 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "warning", + "code": "C216", + "message": "Audit factory 'order_quality' is not referenced by any model and will not produce audits", + "resource_type": "audit", + "resource_name": "order_quality", + "path": "python/audits/quality.py", + "line": 4, + "column": 1, + "location": { + "path": "python/audits/quality.py", + "line": 4, + "column": 1 + } + }, + { + "phase": "compile", + "severity": "error", + "code": "S024", + "message": "Declaration 'constant:minimum_amount' is currently project at 'constants' (constants/limits.sql); required exact-owner-private at 'models/staging'. Consumers: model:stg_orders. Move it to 'models/staging/_sqlbuild/_constants/'", + "path": "constants/limits.sql", + "line": 1, + "column": 1, + "location": { + "path": "constants/limits.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "WHERE amount > 1", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/over-broad-global.json b/tests/goldens/compiler/failure/over-broad-global.json new file mode 100644 index 0000000000..4489bdef1f --- /dev/null +++ b/tests/goldens/compiler/failure/over-broad-global.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S024", + "message": "Declaration 'constant:minimum_amount' is currently project at 'constants' (constants/limits.sql); required exact-owner-private at 'models/staging'. Consumers: model:stg_orders. Move it to 'models/staging/_sqlbuild/_constants/'", + "path": "constants/limits.sql", + "line": 1, + "column": 1, + "location": { + "path": "constants/limits.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "WHERE amount > 1", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/path-defaults-unmatched.json b/tests/goldens/compiler/failure/path-defaults-unmatched.json new file mode 100644 index 0000000000..cbd48e3136 --- /dev/null +++ b/tests/goldens/compiler/failure/path-defaults-unmatched.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "path_defaults['reporting/finance'] does not match any model paths. Known model folders include: marts, staging" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/provider-invalid-settings.json b/tests/goldens/compiler/failure/provider-invalid-settings.json new file mode 100644 index 0000000000..7c7295b81e --- /dev/null +++ b/tests/goldens/compiler/failure/provider-invalid-settings.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D012", + "message": "Provider 'export_settings' in providers/export_settings.py has invalid settings:\napi_token: Field required [missing]" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/python-node-import-error.json b/tests/goldens/compiler/failure/python-node-import-error.json new file mode 100644 index 0000000000..1e4fa38507 --- /dev/null +++ b/tests/goldens/compiler/failure/python-node-import-error.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D011", + "message": "Failed to import Python node file python/tasks/exports.py: No module named 'missing_orders_client'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/python-node-missing-description.json b/tests/goldens/compiler/failure/python-node-missing-description.json new file mode 100644 index 0000000000..139033f6af --- /dev/null +++ b/tests/goldens/compiler/failure/python-node-missing-description.json @@ -0,0 +1,271 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P010", + "message": "task 'export_orders' has no description", + "resource_name": "export_orders", + "path": "python/tasks/exports.py", + "line": 4, + "column": 1, + "location": { + "path": "python/tasks/exports.py", + "line": 4, + "column": 1 + }, + "help": "to describe task 'export_orders', give its function in python/tasks/exports.py a docstring or pass a description to @task:\n @task(description=\"What export_orders does\", ...)" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/python-node-syntax.json b/tests/goldens/compiler/failure/python-node-syntax.json new file mode 100644 index 0000000000..961ba2eae4 --- /dev/null +++ b/tests/goldens/compiler/failure/python-node-syntax.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D011", + "message": "Failed to import Python node file python/tasks/exports.py: invalid syntax (exports.py, line 1)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/python-outside-extension-root.json b/tests/goldens/compiler/failure/python-outside-extension-root.json new file mode 100644 index 0000000000..30a354b381 --- /dev/null +++ b/tests/goldens/compiler/failure/python-outside-extension-root.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D016", + "message": "Unsupported project Python path(s): helpers/formatting.py", + "help": "Move pipeline Python nodes and the helper modules they import under python/, or move SQLBuild extensions under their documented extension path." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/reference-dbt-three-arguments.json b/tests/goldens/compiler/failure/reference-dbt-three-arguments.json new file mode 100644 index 0000000000..b21a746e88 --- /dev/null +++ b/tests/goldens/compiler/failure/reference-dbt-three-arguments.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__dbt_ref(\"shop\", \"orders\", \"extra\") is not a valid __dbt_ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 42 + }, + "help": "__dbt_ref() takes one double-quoted model name, or a double-quoted package name and model name separated by a comma, with no comments or extra spaces inside the parentheses: __dbt_ref(\"package_name\", \"model_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __dbt_ref(\"shop\", \"orders\", \"extra\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-empty-argument.json b/tests/goldens/compiler/failure/reference-empty-argument.json new file mode 100644 index 0000000000..3021f71bd6 --- /dev/null +++ b/tests/goldens/compiler/failure/reference-empty-argument.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(\"stg_orders\", ) is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 27 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"model_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __ref(\"stg_orders\", )", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-error-after-rejected-calls.json b/tests/goldens/compiler/failure/reference-error-after-rejected-calls.json new file mode 100644 index 0000000000..cd15879862 --- /dev/null +++ b/tests/goldens/compiler/failure/reference-error-after-rejected-calls.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/marts/customer_totals.sql:7:39: SQL reference contains an unclosed quoted string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/reference-expression-name.json b/tests/goldens/compiler/failure/reference-expression-name.json new file mode 100644 index 0000000000..de4eaf4ffc --- /dev/null +++ b/tests/goldens/compiler/failure/reference-expression-name.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(concat('stg_', 'orders')) is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 37 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"model_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __ref(concat('stg_', 'orders'))", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-rejected-calls-across-files.json b/tests/goldens/compiler/failure/reference-rejected-calls-across-files.json new file mode 100644 index 0000000000..bc8c93801e --- /dev/null +++ b/tests/goldens/compiler/failure/reference-rejected-calls-across-files.json @@ -0,0 +1,284 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__dbt_ref(shop, orders, extra) is not a valid __dbt_ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 36 + }, + "help": "__dbt_ref() takes one double-quoted model name, or a double-quoted package name and model name separated by a comma, with no comments or extra spaces inside the parentheses: __dbt_ref(\"package_name\", \"model_name\")" + }, + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__table_fn must be followed by an argument list", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 40 + }, + "help": "pass the function arguments in a second set of parentheses, using () for no arguments: __table_fn(\"table_fn__orders_for\")()" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __dbt_ref(shop, orders, extra)", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __table_fn(\"table_fn__orders_for\") -- no call", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-several-rejected-calls-in-one-file.json b/tests/goldens/compiler/failure/reference-several-rejected-calls-in-one-file.json new file mode 100644 index 0000000000..13f1d3968b --- /dev/null +++ b/tests/goldens/compiler/failure/reference-several-rejected-calls-in-one-file.json @@ -0,0 +1,311 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(stg_orders) is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 8, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 8, + "column": 6, + "end_line": 8, + "end_column": 23 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"stg_orders\")" + }, + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__source( 'raw_orders' ) is not a valid __source() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 9, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 9, + "column": 6, + "end_line": 9, + "end_column": 30 + }, + "help": "__source() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __source(\"raw_orders\")" + }, + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__seed(\"a\", \"b\") is not a valid __seed() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 10, + "column": 47, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 10, + "column": 47, + "end_line": 10, + "end_column": 63 + }, + "help": "__seed() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __seed(\"seed_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "-- __ref(hidden)", + "SELECT order_id AS customer_id, 'é __ref(hidden)' AS note, $$__ref(hidden)$$ AS body,", + " 1 AS total_amount /* __ref(hidden) */", + "FROM __ref(stg_orders)", + "JOIN __source( 'raw_orders' ) USING (customer_id)", + "WHERE customer_id IN (SELECT customer_id FROM __seed(\"a\", \"b\"))", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-two-name-arguments.json b/tests/goldens/compiler/failure/reference-two-name-arguments.json new file mode 100644 index 0000000000..a419ba1b44 --- /dev/null +++ b/tests/goldens/compiler/failure/reference-two-name-arguments.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(\"stg_orders\", \"orders\") is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 35 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"model_name\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __ref(\"stg_orders\", \"orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/reference-unclosed-call.json b/tests/goldens/compiler/failure/reference-unclosed-call.json new file mode 100644 index 0000000000..ff28d64647 --- /dev/null +++ b/tests/goldens/compiler/failure/reference-unclosed-call.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/marts/customer_totals.sql:6:6: SQL reference contains an unclosed parenthesis" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/resource-name-collision.json b/tests/goldens/compiler/failure/resource-name-collision.json new file mode 100644 index 0000000000..65d112fa88 --- /dev/null +++ b/tests/goldens/compiler/failure/resource-name-collision.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D007", + "message": "Logical relation name 'stg_orders' is declared as both model in models/staging/stg_orders.sql and seed in seeds/stg_orders.yml" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/rule-custom-finding.json b/tests/goldens/compiler/failure/rule-custom-finding.json new file mode 100644 index 0000000000..fae7d107f4 --- /dev/null +++ b/tests/goldens/compiler/failure/rule-custom-finding.json @@ -0,0 +1,27 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "rule", + "severity": "error", + "code": "XSQBRDIFF001", + "message": "Models avoid the stg_ prefix", + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 1, + "column": 1 + }, + "help": "Rename the model." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/rule-unused-cte.json b/tests/goldens/compiler/failure/rule-unused-cte.json new file mode 100644 index 0000000000..7bf21cd0f3 --- /dev/null +++ b/tests/goldens/compiler/failure/rule-unused-cte.json @@ -0,0 +1,30 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "rule", + "severity": "error", + "code": "SQBRSQL005", + "message": "CTE is unreachable from the final query", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 6 + }, + "help": "Reference the CTE from the final query or another reachable CTE, or remove it.", + "notes": [ + "Fix available: `sqb format --fix` applies it after compiler verification" + ] + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/runtime-placeholder-without-default.json b/tests/goldens/compiler/failure/runtime-placeholder-without-default.json new file mode 100644 index 0000000000..c41ac30c26 --- /dev/null +++ b/tests/goldens/compiler/failure/runtime-placeholder-without-default.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "model 'stg_orders': @@@placeholders without default values in placeholders config: window_start" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-check-reads-source.json b/tests/goldens/compiler/failure/scenario-check-reads-source.json new file mode 100644 index 0000000000..f262a45f84 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-check-reads-source.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario file tests/scenarios/orders.sql CTE '__expected__stg_orders' must not reference project source 'raw_orders' with __source(); source-backed scenario data is only allowed in helper and fixture CTEs" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-dependent-checks.json b/tests/goldens/compiler/failure/scenario-dependent-checks.json new file mode 100644 index 0000000000..e2564dc3e4 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-dependent-checks.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' check CTE '__expected__stg_orders' must not depend on '__assert__no_rows'; expected results and assertions must be independent" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-first-of-two-errors.json b/tests/goldens/compiler/failure/scenario-first-of-two-errors.json new file mode 100644 index 0000000000..10b8363fc0 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-first-of-two-errors.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/a_orders.sql' must use __seed__ to identify a target" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-fixture-without-target.json b/tests/goldens/compiler/failure/scenario-fixture-without-target.json new file mode 100644 index 0000000000..26fa2c8e66 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-fixture-without-target.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' must use __seed__ to identify a target" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-macro-mock.json b/tests/goldens/compiler/failure/scenario-macro-mock.json new file mode 100644 index 0000000000..0282822409 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-macro-mock.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' does not support macro mock CTE '__macro__tidy'. Scenarios run real project macros; use SQL unit tests for macro mocks." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-materialized-cte.json b/tests/goldens/compiler/failure/scenario-materialized-cte.json new file mode 100644 index 0000000000..0844e70d10 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-materialized-cte.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' CTE '__source__raw_orders' must not use AS MATERIALIZED; materialization hints are not supported in SQL scenario CTEs\n --> tests/scenarios/orders.sql:6:25", + "help": "remove MATERIALIZED and write __source__raw_orders AS (...)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-parse.json b/tests/goldens/compiler/failure/scenario-parse.json new file mode 100644 index 0000000000..f9a2ec10b1 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D009", + "message": "SQL scenario '/tests/scenarios/orders.sql' must start with a SCENARIO() header as the first non-whitespace content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-quoted-cte-name.json b/tests/goldens/compiler/failure/scenario-quoted-cte-name.json new file mode 100644 index 0000000000..909d3d072d --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-quoted-cte-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' CTE name \"__source__raw_orders\" must be an unquoted identifier of ASCII letters, digits and underscores\n --> tests/scenarios/orders.sql:6:1", + "help": "rename the CTE, for example __source__raw_orders; quoted CTE names and names with $ or non-ASCII characters are not supported" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-statement-after-ctes.json b/tests/goldens/compiler/failure/scenario-statement-after-ctes.json new file mode 100644 index 0000000000..0a1890b46b --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-statement-after-ctes.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' must end after its CTEs; only an optional ceremonial top-level `SELECT 1` may follow them" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scenario-without-checks.json b/tests/goldens/compiler/failure/scenario-without-checks.json new file mode 100644 index 0000000000..b8f7ce9fe9 --- /dev/null +++ b/tests/goldens/compiler/failure/scenario-without-checks.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' must define at least one __expected__ or __assert__ CTE" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/schema-from-sibling-folder.json b/tests/goldens/compiler/failure/schema-from-sibling-folder.json new file mode 100644 index 0000000000..fb5dc4d694 --- /dev/null +++ b/tests/goldens/compiler/failure/schema-from-sibling-folder.json @@ -0,0 +1,289 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S006", + "message": "Schema 'order_shape' is not visible from 'models/staging/stg_orders.sql'. It is defined at models/marts/_sqlbuild/_schemas/order_shape.sql with local scope owned by 'models/marts'", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "help": "move 'models/marts/_sqlbuild/_schemas/order_shape.sql' to a schemas/ role owned by 'models/staging' or one of its parent folders, or to the project-wide schemas/ when consumers span resource trees" + }, + { + "phase": "compile", + "severity": "error", + "code": "S007", + "message": "Declaration 'schema:order_shape' is currently exact-owner-private at 'models/marts' (models/marts/_sqlbuild/_schemas/order_shape.sql); required exact-owner-private at 'models/staging'. Consumers: model:stg_orders. Move it to 'models/staging/_sqlbuild/_schemas/'", + "path": "models/marts/_sqlbuild/_schemas/order_shape.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/marts/_sqlbuild/_schemas/order_shape.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/schema-unterminated-declaration.json b/tests/goldens/compiler/failure/schema-unterminated-declaration.json new file mode 100644 index 0000000000..82860340ab --- /dev/null +++ b/tests/goldens/compiler/failure/schema-unterminated-declaration.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "/models/staging/_sqlbuild/_schemas/orders.sql has an unterminated declaration header" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/schema-yml-invalid-yaml.json b/tests/goldens/compiler/failure/schema-yml-invalid-yaml.json new file mode 100644 index 0000000000..ae3dc287c4 --- /dev/null +++ b/tests/goldens/compiler/failure/schema-yml-invalid-yaml.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D005", + "message": "/models/marts/schema.yml contains invalid YAML at line 2, column 1: while parsing a node, did not find expected node content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/schema-yml-model-metadata.json b/tests/goldens/compiler/failure/schema-yml-model-metadata.json new file mode 100644 index 0000000000..0d428b077f --- /dev/null +++ b/tests/goldens/compiler/failure/schema-yml-model-metadata.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D005", + "message": "/models/marts/schema.yml declares model metadata in 'models', but model metadata must live in the model file MODEL(...). Move description, columns, and audits into the model header." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-duplicate-scoped-enum.json b/tests/goldens/compiler/failure/scope-duplicate-scoped-enum.json new file mode 100644 index 0000000000..f0290603a8 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-duplicate-scoped-enum.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Invalid declaration scope index:\n[S003] Duplicate declaration 'enum:staged_status' at enums/status.sql:1:1, models/staging/_enums/status.sql:1:1\n[S003] Duplicate declaration 'enum:staged_status' at enums/status.sql:1:1, models/staging/_enums/status.sql:1:1" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-first-of-two-visibility-errors.json b/tests/goldens/compiler/failure/scope-first-of-two-visibility-errors.json new file mode 100644 index 0000000000..e2a6fe7353 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-first-of-two-visibility-errors.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Enum 'staged_status' is known but inaccessible in '/models/marts/customer_totals.sql'. It is defined at models/staging/_enums/status.sql:1:1 with local scope owned by 'models/staging'; consumer path: '/models/marts/customer_totals.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-inaccessible-local-macro.json b/tests/goldens/compiler/failure/scope-inaccessible-local-macro.json new file mode 100644 index 0000000000..c6c2cda986 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-inaccessible-local-macro.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro '@staged_amount' in '/models/marts/customer_totals.sql' is inaccessible. Defined at 'models/staging/_macros/amounts.py:1:1' with scope owner 'models/staging'; consumer/definition path is '/models/marts/customer_totals.sql'. Visible macros: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-macro-test-cte-without-body.json b/tests/goldens/compiler/failure/scope-macro-test-cte-without-body.json new file mode 100644 index 0000000000..0f1d66c006 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-macro-test-cte-without-body.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_customer_totals.sql' CTE '__macro_actual__' must use AS (...)" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-malformed-expected-relationship.json b/tests/goldens/compiler/failure/scope-malformed-expected-relationship.json new file mode 100644 index 0000000000..3bf3e6f32e --- /dev/null +++ b/tests/goldens/compiler/failure/scope-malformed-expected-relationship.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_customer_totals.sql' must use __expected__ to identify a target" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-scenario-expected-without-target.json b/tests/goldens/compiler/failure/scope-scenario-expected-without-target.json new file mode 100644 index 0000000000..a423eb3db6 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-scenario-expected-without-target.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL scenario 'tests/scenarios/orders.sql' must use __expected__ to identify a target" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scope-test-outside-relationship-grant.json b/tests/goldens/compiler/failure/scope-test-outside-relationship-grant.json new file mode 100644 index 0000000000..c0fdc3f0d4 --- /dev/null +++ b/tests/goldens/compiler/failure/scope-test-outside-relationship-grant.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Enum 'staged_status' is known but inaccessible in '/tests/unit/test_customer_totals.sql'. It is defined at models/staging/_enums/status.sql:1:1 with local scope owned by 'models/staging'; consumer path: '/tests/unit/test_customer_totals.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/scoped-root-at-project-root.json b/tests/goldens/compiler/failure/scoped-root-at-project-root.json new file mode 100644 index 0000000000..a2b71957ba --- /dev/null +++ b/tests/goldens/compiler/failure/scoped-root-at-project-root.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D013", + "message": "Scoped declaration root _enums/ must be below a canonical authored root" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/seed-declaration-without-csv.json b/tests/goldens/compiler/failure/seed-declaration-without-csv.json new file mode 100644 index 0000000000..8eb1c9b5d2 --- /dev/null +++ b/tests/goldens/compiler/failure/seed-declaration-without-csv.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D008", + "message": "Seed declaration 'order_channels' in seeds/order_channels.yml has no matching CSV file under seeds/" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/seed-header-mismatch.json b/tests/goldens/compiler/failure/seed-header-mismatch.json new file mode 100644 index 0000000000..d333066a74 --- /dev/null +++ b/tests/goldens/compiler/failure/seed-header-mismatch.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D008", + "message": "seeds/order_channels.csv header ('id', 'name') does not match declared seed columns ('id', 'label') for 'order_channels'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/seed-without-header.json b/tests/goldens/compiler/failure/seed-without-header.json new file mode 100644 index 0000000000..323aeb2ead --- /dev/null +++ b/tests/goldens/compiler/failure/seed-without-header.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D008", + "message": "Seed CSV seeds/lookups.csv has no matching declaration for seed 'lookups' under seeds/**/*.yml" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/seed-yaml-extension.json b/tests/goldens/compiler/failure/seed-yaml-extension.json new file mode 100644 index 0000000000..57cedec1d4 --- /dev/null +++ b/tests/goldens/compiler/failure/seed-yaml-extension.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D005", + "message": "Seed declaration file seeds/order_channels.yaml must use .yml; .yaml is not supported" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/semantic-cursor-inputs-unknown-column.json b/tests/goldens/compiler/failure/semantic-cursor-inputs-unknown-column.json new file mode 100644 index 0000000000..ea2df9429b --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-cursor-inputs-unknown-column.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "cursor_inputs stg_orders references unknown column 'placed_at'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 9, + "column": 16, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 9, + "column": 16 + }, + "help": "change the metadata column name to an existing output column" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "customer_id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-qualified-alias-unknown-column.json b/tests/goldens/compiler/failure/semantic-qualified-alias-unknown-column.json new file mode 100644 index 0000000000..662ed8627a --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-qualified-alias-unknown-column.json @@ -0,0 +1,277 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'amonut' in stg_orders (as o)", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 29, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 29, + "end_line": 5, + "end_column": 35 + }, + "help": "did you mean 'amount'?", + "notes": [ + "stg_orders has: amount, status, customer_id, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT o.customer_id, SUM(o.amonut) AS total_amount", + "FROM __ref(\"stg_orders\") AS o", + "GROUP BY o.customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-recovered-downstream-uses.json b/tests/goldens/compiler/failure/semantic-recovered-downstream-uses.json new file mode 100644 index 0000000000..6a894d3e8f --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-recovered-downstream-uses.json @@ -0,0 +1,278 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'amonut' in raw_orders", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "end_line": 5, + "end_column": 37 + }, + "help": "did you mean 'amount'?", + "notes": [ + "raw_orders has: amount, status, customer_id, order_id", + "1 downstream uses of stg_orders.amount were not checked because of this error" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amonut, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-recovered-uses-through-intermediate.json b/tests/goldens/compiler/failure/semantic-recovered-uses-through-intermediate.json new file mode 100644 index 0000000000..ed37acb33b --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-recovered-uses-through-intermediate.json @@ -0,0 +1,355 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'amonut' in raw_orders", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "end_line": 5, + "end_column": 37 + }, + "help": "did you mean 'amount'?", + "notes": [ + "raw_orders has: amount, status, customer_id, order_id", + "1 downstream uses of stg_orders.amount were not checked because of this error" + ] + } + ] + } + ], + "compiled": { + "models/intermediate/int_orders.sql": [ + "SELECT customer_id, amount * 2 AS doubled_amount", + "FROM __ref(\"stg_orders\")", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(doubled_amount) AS total_amount", + "FROM __ref(\"int_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amonut, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.int_orders": { + "database": null, + "schema": "main", + "name": "int_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/intermediate/int_orders.sql", + "original_file_path": "models/intermediate/int_orders.sql", + "unique_id": "model.failure_corpus.int_orders", + "fqn": [ + "failure_corpus", + "models", + "intermediate", + "int_orders" + ], + "alias": "int_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Doubled order amounts", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.int_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.int_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.int_orders": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.int_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-rejected-opt-out-counts-findings.json b/tests/goldens/compiler/failure/semantic-rejected-opt-out-counts-findings.json new file mode 100644 index 0000000000..588ae44763 --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-rejected-opt-out-counts-findings.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P009", + "message": "`sql_analysis false` is not needed for model 'customer_totals'", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 3, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 3, + "column": 3 + }, + "help": "remove `sql_analysis false` and fix the findings it was hiding: 2 unknown columns, 1 type mismatch (run `sqb compile` to see them)\n = help: to allow `sql_analysis false` on any model, SQL test or audit, set this in sqlbuild_project.toml:\n [settings]\n require_sql_analysis = false", + "notes": [ + "sqlbuild_project.toml sets [settings] require_sql_analysis = true, which only allows `sql_analysis false` on SQL that SQLBuild cannot parse; this model parses successfully." + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(refund) AS total_amount, MAX(amonut) AS top_amount", + "FROM __ref(\"stg_orders\")", + "WHERE status > 5", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-source-cursor-unknown-column.json b/tests/goldens/compiler/failure/semantic-source-cursor-unknown-column.json new file mode 100644 index 0000000000..112420a01c --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-source-cursor-unknown-column.json @@ -0,0 +1,330 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B300", + "message": "cursor_column references unknown column 'loaded_at'", + "resource_type": "source", + "resource_name": "raw_events", + "path": "sources/raw.yml", + "line": 21, + "column": 20, + "location": { + "path": "sources/raw.yml", + "line": 21, + "column": 20 + }, + "help": "change the metadata column name to an existing output column" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.failure_corpus.raw_events": { + "database": null, + "schema": "", + "name": "raw_events", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_events", + "fqn": [ + "failure_corpus", + "raw_events" + ], + "source_name": "raw_events", + "source_description": "", + "loader": "", + "identifier": "raw_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Loaded events.", + "columns": { + "event_id": { + "name": "event_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "load_seq": { + "name": "load_seq", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_events", + "auto_load": false, + "write_strategy": "append", + "cursor_column": "loaded_at" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [], + "source.failure_corpus.raw_events": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-temporal-comparison-help.json b/tests/goldens/compiler/failure/semantic-temporal-comparison-help.json new file mode 100644 index 0000000000..877af0724a --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-temporal-comparison-help.json @@ -0,0 +1,278 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B217", + "message": "Incompatible comparison between TIMESTAMP and INTEGER", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 7, + "column": 7, + "end_line": 7, + "end_column": 23 + }, + "help": "compare with a timestamp, for example TIMESTAMP '2026-04-01'", + "notes": [ + "o.ordered_at is TIMESTAMP, 5 is INTEGER" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT o.customer_id, SUM(o.amount) AS total_amount", + "FROM __ref(\"stg_orders\") AS o", + "WHERE o.ordered_at > 5", + "GROUP BY o.customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status, CAST('2026-01-01' AS TIMESTAMP) AS ordered_at", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-type-error-unchecked-uses.json b/tests/goldens/compiler/failure/semantic-type-error-unchecked-uses.json new file mode 100644 index 0000000000..6b3daf288b --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-type-error-unchecked-uses.json @@ -0,0 +1,278 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B212", + "message": "Arithmetic operation expects NUMERIC-compatible operands, found STRING and INTEGER", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 5, + "column": 31, + "end_line": 5, + "end_column": 41 + }, + "help": "use operands supported by this arithmetic operator, or convert them explicitly", + "notes": [ + "1 downstream output uses were not type-checked because of this error", + "status is TEXT, 1 is INTEGER" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, status + 1 AS amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/semantic-udf-qualified-cast-argument-family.json b/tests/goldens/compiler/failure/semantic-udf-qualified-cast-argument-family.json new file mode 100644 index 0000000000..591093f15e --- /dev/null +++ b/tests/goldens/compiler/failure/semantic-udf-qualified-cast-argument-family.json @@ -0,0 +1,281 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B301", + "message": "Function 'scaled_amount' argument 'p_factor' expects INTEGER, received TEXT; convert the argument explicitly", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 10, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 10 + }, + "help": "align this declared metadata or audit value with the column or argument type" + } + ] + } + ], + "compiled": { + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE MACRO main.scaled_amount(p_amount, p_factor) AS (", + "p_amount * p_factor", + ")", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT o.customer_id,", + " __udf(\"scaled_amount\")(o.amount, CAST(o.status AS VARCHAR)) AS total_amount", + "FROM __ref(\"stg_orders\") AS o", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.scaled_amount", + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [], + "model.failure_corpus.scaled_amount": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/set-operation-width.json b/tests/goldens/compiler/failure/set-operation-width.json new file mode 100644 index 0000000000..216edb4671 --- /dev/null +++ b/tests/goldens/compiler/failure/set-operation-width.json @@ -0,0 +1,272 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B216", + "message": "UNION operands return different column counts: left 2, right 1", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 1 + }, + "help": "return the same number of columns on both sides of this operation" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, amount FROM __ref(\"stg_orders\")", + "UNION ALL", + "SELECT customer_id FROM __ref(\"stg_orders\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/single-quoted-source-name.json b/tests/goldens/compiler/failure/single-quoted-source-name.json new file mode 100644 index 0000000000..85819900ef --- /dev/null +++ b/tests/goldens/compiler/failure/single-quoted-source-name.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__source('raw_orders') is not a valid __source() call", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 28 + }, + "help": "__source() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __source(\"raw_orders\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source('raw_orders')", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/singular-audit-across-trees.json b/tests/goldens/compiler/failure/singular-audit-across-trees.json new file mode 100644 index 0000000000..0609e7b219 --- /dev/null +++ b/tests/goldens/compiler/failure/singular-audit-across-trees.json @@ -0,0 +1,278 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S009", + "message": "Declaration 'singular_audit:totals_have_orders' is currently descendant-public at 'models/marts' (models/marts/_sqlbuild/audits/singular/totals_have_orders.sql); required project at 'top-level root'. References: model:customer_totals, source:raw_orders. Move it to 'top-level audits/singular/'", + "resource_type": "audit", + "resource_name": "totals_have_orders", + "path": "models/marts/_sqlbuild/audits/singular/totals_have_orders.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/marts/_sqlbuild/audits/singular/totals_have_orders.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "audits/singular/totals_have_orders.sql": [ + "SELECT t.customer_id", + "FROM __ref(\"customer_totals\") t", + "LEFT JOIN __source(\"raw_orders\") o ON t.customer_id = o.customer_id", + "WHERE o.customer_id IS NULL", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/singular-audit-one-resource.json b/tests/goldens/compiler/failure/singular-audit-one-resource.json new file mode 100644 index 0000000000..0985d3bfad --- /dev/null +++ b/tests/goldens/compiler/failure/singular-audit-one-resource.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P004", + "message": "Singular audit 'positive_totals' in models/marts/_sqlbuild/audits/singular/positive_totals.sql checks only model 'customer_totals'; singular audits must be cross-resource", + "resource_type": "audit", + "resource_name": "positive_totals", + "path": "models/marts/_sqlbuild/audits/singular/positive_totals.sql", + "help": "attach a generic audit to 'customer_totals' instead: write it in an audits/generic/ role and select FROM @relation, joining @relation to itself for self-join checks" + } + ] + } + ], + "compiled": { + "audits/singular/positive_totals.sql": [ + "SELECT customer_id FROM __ref(\"customer_totals\") WHERE total_amount < 0", + "" + ], + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/snapshot-schema-change-with-contract.json b/tests/goldens/compiler/failure/snapshot-schema-change-with-contract.json new file mode 100644 index 0000000000..c602ead729 --- /dev/null +++ b/tests/goldens/compiler/failure/snapshot-schema-change-with-contract.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "K012", + "message": "model 'stg_orders': snapshot_schema_change=append_new_columns is not valid with contract enforced; add new columns to the contract or set contract none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/source-description-unknown-variable.json b/tests/goldens/compiler/failure/source-description-unknown-variable.json new file mode 100644 index 0000000000..ee3bfbff1d --- /dev/null +++ b/tests/goldens/compiler/failure/source-description-unknown-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "source raw_orders description references unknown variable 'channel'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/source-parse.json b/tests/goldens/compiler/failure/source-parse.json new file mode 100644 index 0000000000..905f62d103 --- /dev/null +++ b/tests/goldens/compiler/failure/source-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D006", + "message": "/sources/raw.yml contains invalid YAML at line 4, column 1: while parsing a node, did not find expected node content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/source-unknown-key.json b/tests/goldens/compiler/failure/source-unknown-key.json new file mode 100644 index 0000000000..b458236a1f --- /dev/null +++ b/tests/goldens/compiler/failure/source-unknown-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D006", + "message": "/sources/raw.yml source has unknown keys: freshnes; allowed keys: audits, columns, contract, cursor_column, database, description, expression, freshness, ingestr, load_batch_size, managed, meta, name, schema, table, type_enforcement, unique_key, write_strategy", + "help": "did you mean 'freshness'?" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/source-unsupported-yaml.json b/tests/goldens/compiler/failure/source-unsupported-yaml.json new file mode 100644 index 0000000000..76820a2e86 --- /dev/null +++ b/tests/goldens/compiler/failure/source-unsupported-yaml.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D006", + "message": "/sources/raw.yml uses YAML that SQLBuild does not support at line 17, column 22: values tagged !!binary", + "help": "SQLBuild reads plain YAML: block and flow mappings and sequences, plain and quoted scalars, literal and folded block scalars, anchors, aliases and merge keys. Rewrite this part in one of those forms." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-function-header.json b/tests/goldens/compiler/failure/sql-function-header.json new file mode 100644 index 0000000000..4b0cd22780 --- /dev/null +++ b/tests/goldens/compiler/failure/sql-function-header.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "FUNCTION(...) in '/functions/sql/is_placed.sql' contains invalid SQLBuild header syntax: expected value at position 42" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-function-missing-returns.json b/tests/goldens/compiler/failure/sql-function-missing-returns.json new file mode 100644 index 0000000000..56078e96cd --- /dev/null +++ b/tests/goldens/compiler/failure/sql-function-missing-returns.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL function file functions/sql/order_label.sql must declare returns" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-function-template-namespace.json b/tests/goldens/compiler/failure/sql-function-template-namespace.json new file mode 100644 index 0000000000..a245f00d16 --- /dev/null +++ b/tests/goldens/compiler/failure/sql-function-template-namespace.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL function functions/sql/order_label.sql returns references unsupported template namespace 'VAR'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-hook-unknown-key.json b/tests/goldens/compiler/failure/sql-hook-unknown-key.json new file mode 100644 index 0000000000..2911434d9e --- /dev/null +++ b/tests/goldens/compiler/failure/sql-hook-unknown-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D014", + "message": "HOOK() in '/hooks/sql/record_refresh.sql:3' has unsupported keys: phase", + "help": "supported keys: description" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-test-glue-inverted-window.json b/tests/goldens/compiler/failure/sql-test-glue-inverted-window.json new file mode 100644 index 0000000000..f4752ebca8 --- /dev/null +++ b/tests/goldens/compiler/failure/sql-test-glue-inverted-window.json @@ -0,0 +1,36 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'inverted_window' in 'tests/unit/test_customer_totals.sql': cursor_start '20' must be before the exclusive cursor_end '10' for model 'windowed_orders'" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/marts/windowed_orders.sql": [ + "SELECT order_id, amount", + "FROM __source(\"raw_orders\")", + "WHERE order_id >= __cursor_start() AND order_id < __cursor_end()", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/sql-test-glue-missing-mock.json b/tests/goldens/compiler/failure/sql-test-glue-missing-mock.json new file mode 100644 index 0000000000..b271f44a27 --- /dev/null +++ b/tests/goldens/compiler/failure/sql-test-glue-missing-mock.json @@ -0,0 +1,280 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "test", + "severity": "error", + "code": "S000", + "message": "test 'totals_without_source': model 'stg_orders' references __source(\"raw_orders\") which has no mock", + "resource_type": "sql_test", + "resource_name": "totals_without_source", + "path": "tests/unit/test_customer_totals.sql" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ], + "tests/_chain_/customer_totals__stg_orders/totals_without_source.sql": [ + "WITH __ref__stg_orders AS (SELECT 10 AS customer_id, 5.0 AS amount),", + "__ref__customer_totals AS (SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref__stg_orders", + "GROUP BY customer_id),", + "__sqb_cte_0 AS (SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")),", + "__actual__customer_totals AS (SELECT * FROM __ref__customer_totals),", + "__expected__customer_totals AS (SELECT 10 AS customer_id, 5.0 AS total_amount),", + "__actual__stg_orders AS (SELECT * FROM __sqb_cte_0),", + "__expected__stg_orders AS (SELECT 10 AS customer_id, 5.0 AS amount)", + "SELECT 0 AS step_index, 'customer_totals' AS model_name, (SELECT COUNT(*) FROM __actual__customer_totals) AS actual_count, (SELECT COUNT(*) FROM __expected__customer_totals) AS expected_count, (SELECT COUNT(*) FROM (SELECT customer_id, total_amount FROM __actual__customer_totals EXCEPT SELECT customer_id, total_amount FROM __expected__customer_totals) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT customer_id, total_amount FROM __expected__customer_totals EXCEPT SELECT customer_id, total_amount FROM __actual__customer_totals) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT customer_id, amount FROM __actual__stg_orders EXCEPT SELECT customer_id, amount FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT customer_id, amount FROM __expected__stg_orders EXCEPT SELECT customer_id, amount FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/sql-test-glue-mock-reads-referencing-helper.json b/tests/goldens/compiler/failure/sql-test-glue-mock-reads-referencing-helper.json new file mode 100644 index 0000000000..66df657efc --- /dev/null +++ b/tests/goldens/compiler/failure/sql-test-glue-mock-reads-referencing-helper.json @@ -0,0 +1,284 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P013", + "message": "SQL test mock '__ref__stg_orders' reads helper CTE 'orders_feed', which calls __source(\"raw_orders\"); mocks and fixtures are defined before the models the test runs, so the helper cannot be resolved for them", + "resource_type": "sql_test", + "resource_name": "mock_reads_helper", + "path": "tests/unit/test_customer_totals.sql", + "line": 4, + "column": 31, + "location": { + "path": "tests/unit/test_customer_totals.sql", + "line": 4, + "column": 31, + "end_line": 4, + "end_column": 53 + }, + "help": "Read a mock by its CTE name instead, for example FROM __source__raw_orders rather than FROM __source(\"raw_orders\"), defining __source__raw_orders AS (SELECT ...) if the test does not mock it, or write the rows of '__ref__stg_orders' directly." + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ], + "tests/customer_totals/mock_reads_helper.sql": [ + "WITH __ref__stg_orders AS (SELECT * FROM orders_feed),", + "__ref__customer_totals AS (SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref__stg_orders", + "GROUP BY customer_id),", + "__actual__customer_totals AS (SELECT * FROM __ref__customer_totals),", + "__expected__customer_totals AS (SELECT 10 AS customer_id, 5.0 AS total_amount)", + "SELECT 0 AS step_index, 'customer_totals' AS model_name, (SELECT COUNT(*) FROM __actual__customer_totals) AS actual_count, (SELECT COUNT(*) FROM __expected__customer_totals) AS expected_count, (SELECT COUNT(*) FROM (SELECT customer_id, total_amount FROM __actual__customer_totals EXCEPT SELECT customer_id, total_amount FROM __expected__customer_totals) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT customer_id, total_amount FROM __expected__customer_totals EXCEPT SELECT customer_id, total_amount FROM __actual__customer_totals) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/sql-test-glue-window-without-cursor-model.json b/tests/goldens/compiler/failure/sql-test-glue-window-without-cursor-model.json new file mode 100644 index 0000000000..2b0c5b3c1f --- /dev/null +++ b/tests/goldens/compiler/failure/sql-test-glue-window-without-cursor-model.json @@ -0,0 +1,30 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'plain_window' in 'tests/unit/test_customer_totals.sql' declares cursor_start or cursor_end, but no model it evaluates uses __cursor_start() or __cursor_end()" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/syntax-function.json b/tests/goldens/compiler/failure/syntax-function.json new file mode 100644 index 0000000000..b6ddf7cd24 --- /dev/null +++ b/tests/goldens/compiler/failure/syntax-function.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL syntax error in function 'scaled_amount' (/functions/sql/scaled_amount.sql): Parse error at line 1, column 21: Expected RParen, got end of input ('') near [* (p_factor]", + "help": "if this SQL is valid for your warehouse, please report it so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/syntax-hook.json b/tests/goldens/compiler/failure/syntax-hook.json new file mode 100644 index 0000000000..d8ab5bfc26 --- /dev/null +++ b/tests/goldens/compiler/failure/syntax-hook.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Polyglot could not parse model 'customer_totals' post_hooks[0] sql(\"record_refresh\") (hooks/sql/record_refresh.sql): Expected table name or subquery, got Where", + "help": "if this SQL is valid for your warehouse, skip SQL analysis for this model, add this to the MODEL header:\n MODEL (\n sql_analysis false,\n ...\n );\n and please report the SQL so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/syntax-inline-hook.json b/tests/goldens/compiler/failure/syntax-inline-hook.json new file mode 100644 index 0000000000..1a52b36985 --- /dev/null +++ b/tests/goldens/compiler/failure/syntax-inline-hook.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Polyglot could not parse model 'customer_totals' post_hooks[0] inline_sql(\"...\") (/models/marts/customer_totals.sql): Expected table name or subquery, got Where", + "help": "if this SQL is valid for your warehouse, skip SQL analysis for this model, add this to the MODEL header:\n MODEL (\n sql_analysis false,\n ...\n );\n and please report the SQL so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/syntax-source-expression.json b/tests/goldens/compiler/failure/syntax-source-expression.json new file mode 100644 index 0000000000..e336422be3 --- /dev/null +++ b/tests/goldens/compiler/failure/syntax-source-expression.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL syntax error in source expression 'raw_orders' (/sources/raw.yml): Parse error at line 1, column 38: Unexpected token: Comma", + "help": "if this SQL is valid for your warehouse, please report it so the parser can support it\n = help: SQL analysis is on for this project; to turn it off for every model, set this in sqlbuild_project.toml:\n [settings]\n sql_analysis = false\n = help: to skip SQL analysis for one run, use `--no-sql-analysis`" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/table-function-arity.json b/tests/goldens/compiler/failure/table-function-arity.json new file mode 100644 index 0000000000..22621bb4fa --- /dev/null +++ b/tests/goldens/compiler/failure/table-function-arity.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/marts/customer_totals.sql table function 'table_fn__orders_for' expects 1 argument but received 2" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/table-function-empty-call-argument.json b/tests/goldens/compiler/failure/table-function-empty-call-argument.json new file mode 100644 index 0000000000..946df88075 --- /dev/null +++ b/tests/goldens/compiler/failure/table-function-empty-call-argument.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/marts/customer_totals.sql:6:6: SQL reference contains an empty argument" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/table-function-single-quoted-name.json b/tests/goldens/compiler/failure/table-function-single-quoted-name.json new file mode 100644 index 0000000000..9b0b2aaa4e --- /dev/null +++ b/tests/goldens/compiler/failure/table-function-single-quoted-name.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__table_fn('table_fn__orders_for') is not a valid __table_fn() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 40 + }, + "help": "__table_fn() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __table_fn(\"table_fn__orders_for\")(...)" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __table_fn('table_fn__orders_for')(1)", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/table-function-unclosed-call.json b/tests/goldens/compiler/failure/table-function-unclosed-call.json new file mode 100644 index 0000000000..233c2dadd1 --- /dev/null +++ b/tests/goldens/compiler/failure/table-function-unclosed-call.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "models/marts/customer_totals.sql:6:6: SQL table function call contains an unclosed parenthesis" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/table-function-without-arguments.json b/tests/goldens/compiler/failure/table-function-without-arguments.json new file mode 100644 index 0000000000..8ce7a7e6a3 --- /dev/null +++ b/tests/goldens/compiler/failure/table-function-without-arguments.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__table_fn must be followed by an argument list", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 40 + }, + "help": "pass the function arguments in a second set of parentheses, using () for no arguments: __table_fn(\"table_fn__orders_for\")()" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT order_id AS customer_id, 1 AS total_amount", + "FROM __table_fn(\"table_fn__orders_for\") /* no call */", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/target-managed-loader-collision.json b/tests/goldens/compiler/failure/target-managed-loader-collision.json new file mode 100644 index 0000000000..0d0215bd07 --- /dev/null +++ b/tests/goldens/compiler/failure/target-managed-loader-collision.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S102", + "message": "Managed loader write collision: targets 'dev' and 'prod' both resolve to database='failure.duckdb' schema='raw'. Set distinct targets.dev.loader_schema and targets.prod.loader_schema values." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/target-missing-database.json b/tests/goldens/compiler/failure/target-missing-database.json new file mode 100644 index 0000000000..3fce7f186c --- /dev/null +++ b/tests/goldens/compiler/failure/target-missing-database.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S101", + "message": "snowflake execution requires explicit target database. model 'customer_totals' resolved to database=None schema='ANALYTICS'. Set them in the model config, the environment config, or the project defaults.", + "help": "to set project-wide defaults, set this in sqlbuild_project.toml:\n [defaults]\n database = \"my_database\"" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/target-missing-write-schema.json b/tests/goldens/compiler/failure/target-missing-write-schema.json new file mode 100644 index 0000000000..dc9dd0833a --- /dev/null +++ b/tests/goldens/compiler/failure/target-missing-write-schema.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S103", + "message": "Model 'customer_totals' has no explicitly resolved physical write schema. Set schema on the resource or its defaults, selected target, loader_schema, or connection." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/target-named-without-schema.json b/tests/goldens/compiler/failure/target-named-without-schema.json new file mode 100644 index 0000000000..f256f489be --- /dev/null +++ b/tests/goldens/compiler/failure/target-named-without-schema.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S104", + "message": "Named target 'dev' must explicitly set schema to a nonblank literal or 'preserve'. Resource schemas, defaults, and connection schemas do not select a named target schema strategy." + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/target-unknown-key.json b/tests/goldens/compiler/failure/target-unknown-key.json new file mode 100644 index 0000000000..238270d0ba --- /dev/null +++ b/tests/goldens/compiler/failure/target-unknown-key.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D001", + "message": "/sqlbuild_project.toml targets.ci contains unknown key(s): warehouse_size. Allowed keys: clone, compile_cache, connection, database, default_table_type, defer_clone_from, defer_sources_to, diff, execution_limits, loader_schema, missing_migration_origin, owns_time_travel_retention_namespace, schema, table_type_downgrade, time_travel_retention, time_travel_retention_decrease, vars, warehouses", + "help": "did you mean 'warehouses'?" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-assertion-reads-unmocked-source.json b/tests/goldens/compiler/failure/test-assertion-reads-unmocked-source.json new file mode 100644 index 0000000000..0d989d6ad8 --- /dev/null +++ b/tests/goldens/compiler/failure/test-assertion-reads-unmocked-source.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P013", + "message": "SQL test assertion CTE '__assert__no_negative_orders' calls __source(\"raw_orders\"), which the test does not mock, so the test query cannot resolve it", + "resource_type": "sql_test", + "resource_name": "test_customer_totals", + "path": "tests/unit/test_customer_totals.sql", + "line": 11, + "column": 24, + "location": { + "path": "tests/unit/test_customer_totals.sql", + "line": 11, + "column": 24, + "end_line": 11, + "end_column": 46 + }, + "help": "Mock it in the test, for example __source__raw_orders AS (SELECT ...), or remove the call from assertion CTE '__assert__no_negative_orders'." + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/test-case-missing-parameter.json b/tests/goldens/compiler/failure/test-case-missing-parameter.json new file mode 100644 index 0000000000..36f1373446 --- /dev/null +++ b/tests/goldens/compiler/failure/test-case-missing-parameter.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D003", + "message": "TEST() case 'placed' in '/tests/unit/test_order_cases.sql' is missing parameters: amount_value" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-expected-implicit-alias.json b/tests/goldens/compiler/failure/test-expected-implicit-alias.json new file mode 100644 index 0000000000..29a4c61e16 --- /dev/null +++ b/tests/goldens/compiler/failure/test-expected-implicit-alias.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_stg_orders.sql' must alias every non-trivial __expected__stg_orders projection", + "help": "name the column with an alias, for example amount IS NULL AS ; only a bare or qualified column reference may go unaliased" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-expected-parenthesised-branch.json b/tests/goldens/compiler/failure/test-expected-parenthesised-branch.json new file mode 100644 index 0000000000..a777cb689c --- /dev/null +++ b/tests/goldens/compiler/failure/test-expected-parenthesised-branch.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_stg_orders.sql' must write each __expected__stg_orders set-operation branch as a plain SELECT without enclosing parentheses" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-expected-reads-unknown-model.json b/tests/goldens/compiler/failure/test-expected-reads-unknown-model.json new file mode 100644 index 0000000000..fabb28be9c --- /dev/null +++ b/tests/goldens/compiler/failure/test-expected-reads-unknown-model.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P013", + "message": "SQL test expected CTE '__expected__stg_orders' references unknown model 'archived_orders'", + "resource_type": "sql_test", + "resource_name": "test_stg_orders", + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "location": { + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "end_line": 8, + "end_column": 48 + }, + "help": "Read a model defined in the project, for example __ref(\"\"), or remove the reference from expected CTE '__expected__stg_orders'." + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/test-expected-unknown-column.json b/tests/goldens/compiler/failure/test-expected-unknown-column.json new file mode 100644 index 0000000000..c1e0924657 --- /dev/null +++ b/tests/goldens/compiler/failure/test-expected-unknown-column.json @@ -0,0 +1,283 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B302", + "message": "SQL test '__expected__stg_orders' names unknown column 'discount'", + "resource_type": "sql_test", + "resource_name": "test_stg_orders", + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 30, + "location": { + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 30, + "end_line": 8, + "end_column": 38 + }, + "help": "align the SQL-test fixture or expected columns with the tested resource's output" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ], + "tests/stg_orders/test_stg_orders.sql": [ + "WITH __source__raw_orders AS (SELECT 1 AS order_id, 10 AS customer_id, CAST(5 AS DOUBLE) AS amount, 'placed' AS status),", + "__ref__stg_orders AS (SELECT order_id, customer_id, amount, status", + "FROM __source__raw_orders),", + "__actual__stg_orders AS (SELECT * FROM __ref__stg_orders),", + "__expected__stg_orders AS (SELECT 1 AS order_id, 2 AS discount)", + "SELECT 0 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, discount FROM __actual__stg_orders EXCEPT SELECT order_id, discount FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, discount FROM __expected__stg_orders EXCEPT SELECT order_id, discount FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/test-expects-unknown-model.json b/tests/goldens/compiler/failure/test-expects-unknown-model.json new file mode 100644 index 0000000000..b39f388d2b --- /dev/null +++ b/tests/goldens/compiler/failure/test-expects-unknown-model.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test file tests/unit/test_stg_payments.sql expects unknown model 'stg_payments'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-helper-reads-unknown-model.json b/tests/goldens/compiler/failure/test-helper-reads-unknown-model.json new file mode 100644 index 0000000000..be0c3d62df --- /dev/null +++ b/tests/goldens/compiler/failure/test-helper-reads-unknown-model.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P013", + "message": "SQL test helper CTE 'archived_orders' references unknown model 'archived_orders'", + "resource_type": "sql_test", + "resource_name": "test_stg_orders", + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "location": { + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "end_line": 8, + "end_column": 48 + }, + "help": "Read a model defined in the project, for example __ref(\"\"), or remove the reference from helper CTE 'archived_orders'." + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/test-mocks-unknown-source.json b/tests/goldens/compiler/failure/test-mocks-unknown-source.json new file mode 100644 index 0000000000..fb0c37c930 --- /dev/null +++ b/tests/goldens/compiler/failure/test-mocks-unknown-source.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test file tests/unit/test_stg_orders.sql mocks unknown source 'raw_payments'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-parse.json b/tests/goldens/compiler/failure/test-parse.json new file mode 100644 index 0000000000..868397b0a6 --- /dev/null +++ b/tests/goldens/compiler/failure/test-parse.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D003", + "message": "SQL test '/tests/unit/test_stg_orders.sql' must start with a TEST() header as the first non-whitespace content" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-quoted-cte-name.json b/tests/goldens/compiler/failure/test-quoted-cte-name.json new file mode 100644 index 0000000000..0fa006a626 --- /dev/null +++ b/tests/goldens/compiler/failure/test-quoted-cte-name.json @@ -0,0 +1,19 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL test 'tests/unit/test_stg_orders.sql' CTE name \"recent orders\" must be an unquoted identifier of ASCII letters, digits and underscores\n --> tests/unit/test_stg_orders.sql:7:1", + "help": "rename the CTE, for example recent_orders; quoted CTE names and names with $ or non-ASCII characters are not supported" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/test-reads-only-mocks.json b/tests/goldens/compiler/failure/test-reads-only-mocks.json new file mode 100644 index 0000000000..d91fc257f0 --- /dev/null +++ b/tests/goldens/compiler/failure/test-reads-only-mocks.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P013", + "message": "SQL test 'test_stg_orders' mocks the model it tests (__ref__stg_orders), so the test has no model to run against", + "resource_type": "sql_test", + "resource_name": "test_stg_orders", + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "location": { + "path": "tests/unit/test_stg_orders.sql", + "line": 8, + "column": 24, + "end_line": 8, + "end_column": 43 + }, + "help": "Mock the model's inputs instead (for example __source__ or __ref__) and keep __ref(\"stg_orders\") in the __assert__ or __expected__ CTE, or remove the test." + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/unclosed-dollar-quote-with-project-variable.json b/tests/goldens/compiler/failure/unclosed-dollar-quote-with-project-variable.json new file mode 100644 index 0000000000..a9e5ec93cd --- /dev/null +++ b/tests/goldens/compiler/failure/unclosed-dollar-quote-with-project-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "SQL interpolation contains an unclosed quoted string" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/ungrouped-column.json b/tests/goldens/compiler/failure/ungrouped-column.json new file mode 100644 index 0000000000..7c623a89c5 --- /dev/null +++ b/tests/goldens/compiler/failure/ungrouped-column.json @@ -0,0 +1,274 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B230", + "message": "Column must be grouped or used in an aggregate function", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 21, + "end_line": 5, + "end_column": 27 + }, + "help": "add this expression to GROUP BY or use it inside an aggregate" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, status, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/unknown-column.json b/tests/goldens/compiler/failure/unknown-column.json new file mode 100644 index 0000000000..3a592e9c09 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-column.json @@ -0,0 +1,276 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "B002", + "message": "Unknown column 'discount' in stg_orders", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 5, + "column": 25, + "end_line": 5, + "end_column": 33 + }, + "notes": [ + "stg_orders has: amount, customer_id, status, order_id" + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(discount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/unknown-constant.json b/tests/goldens/compiler/failure/unknown-constant.json new file mode 100644 index 0000000000..5c030968f4 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-constant.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown constant 'minimum_amount' in '/models/staging/stg_orders.sql'. Visible constants: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-enum-member.json b/tests/goldens/compiler/failure/unknown-enum-member.json new file mode 100644 index 0000000000..893223e5ee --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-enum-member.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown member 'RETURNED' for enum 'order_status' in '/models/staging/stg_orders.sql'. Available members: PLACED, SHIPPED" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-macro.json b/tests/goldens/compiler/failure/unknown-macro.json new file mode 100644 index 0000000000..adbe60f253 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-macro.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown macro '@cents' in '/models/staging/stg_orders.sql'. Available macros: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-ref.json b/tests/goldens/compiler/failure/unknown-ref.json new file mode 100644 index 0000000000..7ae331d589 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-ref.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/marts/customer_totals.sql references unknown model 'stg_payments'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-scalar-function.json b/tests/goldens/compiler/failure/unknown-scalar-function.json new file mode 100644 index 0000000000..1a6bb7ca94 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-scalar-function.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/staging/stg_orders.sql references unknown SQL function 'is_large'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-source.json b/tests/goldens/compiler/failure/unknown-source.json new file mode 100644 index 0000000000..b62cf8f45d --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-source.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/staging/stg_orders.sql references unknown source 'raw_payments'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unknown-table-function.json b/tests/goldens/compiler/failure/unknown-table-function.json new file mode 100644 index 0000000000..73f39c7925 --- /dev/null +++ b/tests/goldens/compiler/failure/unknown-table-function.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/marts/customer_totals.sql references unknown table function 'table_fn__missing'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unneeded-sql-analysis-opt-out.json b/tests/goldens/compiler/failure/unneeded-sql-analysis-opt-out.json new file mode 100644 index 0000000000..623f4193a5 --- /dev/null +++ b/tests/goldens/compiler/failure/unneeded-sql-analysis-opt-out.json @@ -0,0 +1,275 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P009", + "message": "`sql_analysis false` is not needed for model 'stg_orders'", + "resource_type": "model", + "resource_name": "stg_orders", + "path": "models/staging/stg_orders.sql", + "line": 3, + "column": 3, + "location": { + "path": "models/staging/stg_orders.sql", + "line": 3, + "column": 3 + }, + "help": "remove `sql_analysis false`; it is not hiding any findings\n = help: to allow `sql_analysis false` on any model, SQL test or audit, set this in sqlbuild_project.toml:\n [settings]\n require_sql_analysis = false", + "notes": [ + "sqlbuild_project.toml sets [settings] require_sql_analysis = true, which only allows `sql_analysis false` on SQL that SQLBuild cannot parse; this model parses successfully." + ] + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/unquoted-ref-name.json b/tests/goldens/compiler/failure/unquoted-ref-name.json new file mode 100644 index 0000000000..11c1f3b0c7 --- /dev/null +++ b/tests/goldens/compiler/failure/unquoted-ref-name.json @@ -0,0 +1,270 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P012", + "message": "__ref(stg_orders) is not a valid __ref() call", + "resource_type": "model", + "resource_name": "customer_totals", + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "location": { + "path": "models/marts/customer_totals.sql", + "line": 6, + "column": 6, + "end_line": 6, + "end_column": 23 + }, + "help": "__ref() takes exactly one double-quoted name, with no comments or extra spaces inside the parentheses: __ref(\"stg_orders\")" + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(stg_orders)", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/unset-environment-variable.json b/tests/goldens/compiler/failure/unset-environment-variable.json new file mode 100644 index 0000000000..330dd64b66 --- /dev/null +++ b/tests/goldens/compiler/failure/unset-environment-variable.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown environment variable '@@ENV:SQB_DIFFERENTIAL_UNSET' in '/models/staging/stg_orders.sql'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/failure/unused-declaration.json b/tests/goldens/compiler/failure/unused-declaration.json new file mode 100644 index 0000000000..8daa69c5ed --- /dev/null +++ b/tests/goldens/compiler/failure/unused-declaration.json @@ -0,0 +1,269 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "S010", + "message": "Unused local declaration 'constant:spare' at models/staging/_sqlbuild/_constants/limits.sql; remove it or add a genuine runtime use", + "path": "models/staging/_sqlbuild/_constants/limits.sql", + "line": 1, + "column": 1, + "location": { + "path": "models/staging/_sqlbuild/_constants/limits.sql", + "line": 1, + "column": 1 + } + } + ] + } + ], + "compiled": { + "models/marts/customer_totals.sql": [ + "SELECT customer_id, SUM(amount) AS total_amount", + "FROM __ref(\"stg_orders\")", + "GROUP BY customer_id", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT order_id, customer_id, amount, status", + "FROM __source(\"raw_orders\")", + "" + ] + }, + "manifest": { + "nodes": { + "model.failure_corpus.customer_totals": { + "database": null, + "schema": "main", + "name": "customer_totals", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/marts/customer_totals.sql", + "original_file_path": "models/marts/customer_totals.sql", + "unique_id": "model.failure_corpus.customer_totals", + "fqn": [ + "failure_corpus", + "models", + "marts", + "customer_totals" + ], + "alias": "customer_totals", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Order totals per customer", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_totals", + "depends_on": { + "macros": [], + "nodes": [ + "model.failure_corpus.stg_orders" + ] + } + }, + "model.failure_corpus.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "failure_corpus", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.failure_corpus.stg_orders", + "fqn": [ + "failure_corpus", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Staged orders", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.failure_corpus.raw_orders" + ] + } + } + }, + "sources": { + "source.failure_corpus.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "failure_corpus", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.failure_corpus.raw_orders", + "fqn": [ + "failure_corpus", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Orders feed.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.failure_corpus.customer_totals": [ + "model.failure_corpus.stg_orders" + ], + "model.failure_corpus.stg_orders": [ + "source.failure_corpus.raw_orders" + ], + "source.failure_corpus.raw_orders": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/failure/variable-not-defined.json b/tests/goldens/compiler/failure/variable-not-defined.json new file mode 100644 index 0000000000..4054304f5e --- /dev/null +++ b/tests/goldens/compiler/failure/variable-not-defined.json @@ -0,0 +1,18 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "unknown project variable '@@region' in '/models/staging/stg_orders.sql'. Available vars: none" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/fixture/dbt_interop.json b/tests/goldens/compiler/fixture/dbt_interop.json new file mode 100644 index 0000000000..0bd687b95e --- /dev/null +++ b/tests/goldens/compiler/fixture/dbt_interop.json @@ -0,0 +1,66 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/marts/downstream_orders.sql uses __dbt_ref(\"fact_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + }, + { + "label": "compile-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/marts/downstream_orders.sql uses __dbt_ref(\"fact_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/marts/downstream_orders.sql uses __dbt_ref(\"fact_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + }, + { + "label": "plan", + "exit_code": 1, + "diagnostics": [ + "Project discovery START", + "Project assembly START", + "Declaration parsing START", + "Declaration parsing OK ()", + "Python discovery START", + "Python discovery OK ()", + "Project assembly OK ()", + "Project discovery OK ()", + "External manifest discovery START", + "External manifest discovery OK ()", + "Compiling project...", + "error[C214]: Model file models/marts/downstream_orders.sql uses __dbt_ref(\"fact_orders\") but no dbt manifest was found", + " = help: Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json.", + "", + "" + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/fixture/source_loader_strategies.json b/tests/goldens/compiler/fixture/source_loader_strategies.json new file mode 100644 index 0000000000..122ad0c76d --- /dev/null +++ b/tests/goldens/compiler/fixture/source_loader_strategies.json @@ -0,0 +1,368 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": {}, + "manifest": { + "nodes": {}, + "sources": { + "source.source_loader_strategies.raw_countries": { + "database": null, + "schema": "", + "name": "raw_countries", + "resource_type": "source", + "package_name": "source_loader_strategies", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.source_loader_strategies.raw_countries", + "fqn": [ + "source_loader_strategies", + "raw_countries" + ], + "source_name": "raw_countries", + "source_description": "", + "loader": "", + "identifier": "raw_countries", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_countries.", + "columns": { + "country_id": { + "name": "country_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "country_code": { + "name": "country_code", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "country_name": { + "name": "country_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_countries", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.source_loader_strategies.raw_webhook_events": { + "database": null, + "schema": "", + "name": "raw_webhook_events", + "resource_type": "source", + "package_name": "source_loader_strategies", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.source_loader_strategies.raw_webhook_events", + "fqn": [ + "source_loader_strategies", + "raw_webhook_events" + ], + "source_name": "raw_webhook_events", + "source_description": "", + "loader": "", + "identifier": "raw_webhook_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_webhook_events.", + "columns": { + "event_id": { + "name": "event_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "event_name": { + "name": "event_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_webhook_events", + "auto_load": false, + "write_strategy": "append" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.source_loader_strategies.raw_order_events": { + "database": null, + "schema": "", + "name": "raw_order_events", + "resource_type": "source", + "package_name": "source_loader_strategies", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.source_loader_strategies.raw_order_events", + "fqn": [ + "source_loader_strategies", + "raw_order_events" + ], + "source_name": "raw_order_events", + "source_description": "", + "loader": "", + "identifier": "raw_order_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_order_events.", + "columns": { + "event_id": { + "name": "event_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "event_at": { + "name": "event_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount_cents": { + "name": "amount_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_order_events", + "auto_load": false, + "write_strategy": "delete_insert", + "cursor_column": "event_at" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.source_loader_strategies.raw_customers": { + "database": null, + "schema": "", + "name": "raw_customers", + "resource_type": "source", + "package_name": "source_loader_strategies", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.source_loader_strategies.raw_customers", + "fqn": [ + "source_loader_strategies", + "raw_customers" + ], + "source_name": "raw_customers", + "source_description": "", + "loader": "", + "identifier": "raw_customers", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_customers.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "plan_name": { + "name": "plan_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "updated_at": { + "name": "updated_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_customers", + "auto_load": false, + "write_strategy": "merge", + "cursor_column": "updated_at", + "unique_key": [ + "customer_id" + ] + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.source_loader_strategies.raw_loader_status": { + "database": null, + "schema": "", + "name": "raw_loader_status", + "resource_type": "source", + "package_name": "source_loader_strategies", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.source_loader_strategies.raw_loader_status", + "fqn": [ + "source_loader_strategies", + "raw_loader_status" + ], + "source_name": "raw_loader_status", + "source_description": "", + "loader": "", + "identifier": "raw_loader_status", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_loader_status.", + "columns": { + "status_id": { + "name": "status_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status_name": { + "name": "status_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "loaded_by": { + "name": "loaded_by", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_loader_status", + "auto_load": false + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": {}, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "source.source_loader_strategies.raw_countries": [], + "source.source_loader_strategies.raw_webhook_events": [], + "source.source_loader_strategies.raw_order_events": [], + "source.source_loader_strategies.raw_customers": [], + "source.source_loader_strategies.raw_loader_status": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/fixture/waffle_shop.json b/tests/goldens/compiler/fixture/waffle_shop.json new file mode 100644 index 0000000000..01bd0de7a2 --- /dev/null +++ b/tests/goldens/compiler/fixture/waffle_shop.json @@ -0,0 +1,2110 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/customer_status_snapshot/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"customer_status_snapshot\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/customer_status_snapshot/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"customer_status_snapshot\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/daily_activity_rollup/daily_orders_placed_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"daily_activity_rollup\")", + "WHERE NOT (orders_placed >= 0)", + "" + ], + "audits/generic/daily_activity_rollup/not_null__activity_day.sql": [ + "SELECT activity_day", + "FROM __ref(\"daily_activity_rollup\")", + "WHERE activity_day IS NULL", + "" + ], + "audits/generic/daily_order_partitioned/not_null__order_date.sql": [ + "SELECT order_date", + "FROM __ref(\"daily_order_partitioned\")", + "WHERE order_date IS NULL", + "" + ], + "audits/generic/daily_order_partitioned/waffles_ordered_is_positive.sql": [ + "SELECT *", + "FROM __ref(\"daily_order_partitioned\")", + "WHERE NOT (waffles_ordered > 0)", + "" + ], + "audits/generic/daily_revenue/revenue_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"daily_revenue\")", + "WHERE NOT (total_revenue_cents >= 0)", + "" + ], + "audits/generic/dim_customers/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"dim_customers\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/dim_customers/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"dim_customers\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/fact_orders/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"fact_orders\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/hourly_activity_with_daily_context/day_orders_cover_hourly_orders.sql": [ + "SELECT *", + "FROM __ref(\"hourly_activity_with_daily_context\")", + "WHERE NOT (day_orders_placed >= orders_placed)", + "" + ], + "audits/generic/hourly_activity_with_daily_context/not_null__activity_hour.sql": [ + "SELECT activity_hour", + "FROM __ref(\"hourly_activity_with_daily_context\")", + "WHERE activity_hour IS NULL", + "" + ], + "audits/generic/hourly_order_activity/not_null__activity_hour.sql": [ + "SELECT activity_hour", + "FROM __ref(\"hourly_order_activity\")", + "WHERE activity_hour IS NULL", + "" + ], + "audits/generic/hourly_order_activity/orders_placed_is_non_negative.sql": [ + "SELECT *", + "FROM __ref(\"hourly_order_activity\")", + "WHERE NOT (orders_placed >= 0)", + "" + ], + "audits/generic/order_status_index/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"order_status_index\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/order_status_index/unique__order_id.sql": [ + "SELECT order_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"order_status_index\")", + "WHERE order_id IS NOT NULL", + "GROUP BY order_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_customers/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_customers\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/stg_customers/not_null__email.sql": [ + "SELECT email", + "FROM __ref(\"stg_customers\")", + "WHERE email IS NULL", + "" + ], + "audits/generic/stg_customers/unique__customer_id.sql": [ + "SELECT customer_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_customers\")", + "WHERE customer_id IS NOT NULL", + "GROUP BY customer_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_orders/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"stg_orders\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'preparing', 'ready', 'completed', 'cancelled')", + "" + ], + "audits/generic/stg_orders/not_null__customer_id.sql": [ + "SELECT customer_id", + "FROM __ref(\"stg_orders\")", + "WHERE customer_id IS NULL", + "" + ], + "audits/generic/stg_orders/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_orders\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/stg_orders/relationships__waffle_type_id.sql": [ + "SELECT waffle_type_id", + "FROM __ref(\"stg_orders\")", + "WHERE waffle_type_id IS NOT NULL", + " AND waffle_type_id NOT IN (", + " SELECT waffle_type_id", + " FROM __seed(\"waffle_types\")", + " WHERE waffle_type_id IS NOT NULL", + " )", + "" + ], + "audits/generic/stg_orders/unique__order_id.sql": [ + "SELECT order_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_orders\")", + "WHERE order_id IS NOT NULL", + "GROUP BY order_id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_payments/not_null__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_payments\")", + "WHERE order_id IS NULL", + "" + ], + "audits/generic/stg_payments/not_null__payment_id.sql": [ + "SELECT payment_id", + "FROM __ref(\"stg_payments\")", + "WHERE payment_id IS NULL", + "" + ], + "audits/generic/stg_payments/relationships__order_id.sql": [ + "SELECT order_id", + "FROM __ref(\"stg_payments\")", + "WHERE order_id IS NOT NULL", + " AND order_id NOT IN (", + " SELECT id", + " FROM __source(\"raw_orders\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/stg_payments/unique__payment_id.sql": [ + "SELECT payment_id, COUNT(*) AS duplicate_count", + "FROM __ref(\"stg_payments\")", + "WHERE payment_id IS NOT NULL", + "GROUP BY payment_id", + "HAVING COUNT(*) > 1", + "" + ], + "functions/python/is_completed_order_py.sql": [ + "REGISTER PYTHON FUNCTION is_completed_order_py(STRING) RETURNS BOOLEAN", + "" + ], + "functions/sql/customer_orders.sql": [ + "CREATE OR REPLACE MACRO main.customer_orders(p_customer_id) AS TABLE", + "SELECT", + " order_id,", + " ordered_at,", + " waffle_name,", + " line_total_cents,", + " order_status,", + " is_completed_order", + "FROM __ref(\"fact_orders\")", + "WHERE customer_id = p_customer_id", + "" + ], + "functions/sql/is_completed_order.sql": [ + "CREATE OR REPLACE MACRO main.is_completed_order(order_status) AS (", + "order_status = 'completed'", + ")", + "" + ], + "models/intermediate/customer_status_snapshot.sql": [ + "SELECT", + " customer_id,", + " MAX(ordered_at) AS last_ordered_at,", + " MAX(order_status) AS latest_order_status,", + " COUNT(*) AS total_orders,", + " SUM(line_total_cents) AS total_revenue_cents", + "FROM __ref(\"fact_orders\")", + "GROUP BY customer_id", + "" + ], + "models/intermediate/order_status_index.sql": [ + "SELECT", + " order_id,", + " customer_id,", + " order_status,", + " ordered_at,", + " line_total_cents", + "FROM __ref(\"fact_orders\")", + "" + ], + "models/marts/daily_activity_rollup.sql": [ + "SELECT", + " DATE_TRUNC('day', activity_hour) AS activity_day,", + " SUM(orders_placed) AS orders_placed,", + " SUM(waffles_ordered) AS waffles_ordered,", + " SUM(revenue_cents) AS revenue_cents", + "FROM __ref(\"hourly_order_activity\")", + "GROUP BY DATE_TRUNC('day', activity_hour)", + "" + ], + "models/marts/daily_order_partitioned.sql": [ + "SELECT", + " CAST(o.ordered_at AS DATE) AS order_date,", + " COUNT(DISTINCT o.order_id) AS order_count,", + " SUM(o.quantity) AS waffles_ordered,", + " COUNT(DISTINCT o.customer_id) AS unique_customers", + "FROM __ref(\"stg_orders\") o", + "WHERE CAST(o.ordered_at AS DATE) >= CAST(@@@partition_start AS DATE)", + " AND CAST(o.ordered_at AS DATE) < CAST(@@@partition_end AS DATE)", + "GROUP BY CAST(o.ordered_at AS DATE)", + "" + ], + "models/marts/daily_revenue.sql": [ + "SELECT", + " CAST(o.ordered_at AS DATE) AS revenue_date,", + " COUNT(DISTINCT o.order_id) AS order_count,", + " SUM(o.quantity) AS waffles_sold,", + " SUM(p.amount_cents) AS total_revenue_cents,", + " SUM(p.amount_cents) / COUNT(DISTINCT o.order_id) AS avg_order_value_cents", + "FROM __ref(\"stg_orders\") o", + "INNER JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id AND p.payment_status = 'success'", + "GROUP BY CAST(o.ordered_at AS DATE)", + "" + ], + "models/marts/dim_customers.sql": [ + "SELECT", + " c.customer_id,", + " c.first_name,", + " c.last_name,", + " c.email,", + " c.created_at AS customer_since,", + " COUNT(DISTINCT o.order_id) AS lifetime_orders,", + " COALESCE(SUM(p.amount_cents), 0) AS lifetime_spend_cents", + "FROM __ref(\"stg_customers\") c", + "LEFT JOIN __ref(\"stg_orders\") o ON c.customer_id = o.customer_id", + "LEFT JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id AND p.payment_status = 'success'", + "GROUP BY c.customer_id, c.first_name, c.last_name, c.email, c.created_at", + "" + ], + "models/marts/fact_orders.sql": [ + "SELECT", + " o.order_id,", + " o.customer_id,", + " o.waffle_type_id,", + " w.waffle_name,", + " w.category AS waffle_category,", + " o.quantity,", + " w.price_cents * o.quantity AS line_total_cents,", + " o.ordered_at,", + " o.status AS order_status,", + " __udf(\"is_completed_order\")(o.status) AS is_completed_order,", + " __udf(\"is_completed_order_py\")(o.status) AS is_completed_order_py,", + " p.payment_method,", + " p.payment_status,", + " p.amount_cents AS payment_amount_cents", + "FROM __ref(\"stg_orders\") o", + "LEFT JOIN __seed(\"waffle_types\") w ON o.waffle_type_id = w.waffle_type_id", + "LEFT JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id", + "" + ], + "models/marts/hourly_activity_with_daily_context.sql": [ + "SELECT", + " h.activity_hour,", + " h.orders_placed,", + " d.orders_placed AS day_orders_placed,", + " h.waffles_ordered,", + " h.revenue_cents", + "FROM __ref(\"hourly_order_activity\") h", + "INNER JOIN __ref(\"daily_activity_rollup\") d", + " ON DATE_TRUNC('day', h.activity_hour) = d.activity_day", + "" + ], + "models/marts/hourly_order_activity.sql": [ + "SELECT", + " DATE_TRUNC('hour', o.ordered_at) AS activity_hour,", + " COUNT(*) AS orders_placed,", + " SUM(o.quantity) AS waffles_ordered,", + " SUM(o.line_total_cents) AS revenue_cents", + "FROM __ref(\"fact_orders\") o", + "GROUP BY DATE_TRUNC('hour', o.ordered_at)", + "" + ], + "models/marts/scenario_order_prices.sql": [ + "SELECT", + " o.order_id,", + " o.quantity,", + " w.waffle_name,", + " w.price_cents,", + " w.price_cents * o.quantity AS line_total_cents,", + " p.amount_cents AS payment_amount_cents", + "FROM __ref(\"stg_orders\") o", + "INNER JOIN __seed(\"waffle_types\") w ON o.waffle_type_id = w.waffle_type_id", + "LEFT JOIN __ref(\"stg_payments\") p ON o.order_id = p.order_id", + "" + ], + "models/staging/stg_customers.sql": [ + "SELECT", + " id AS customer_id,", + " first_name,", + " last_name,", + " email,", + " created_at", + "FROM __source(\"raw_customers\")", + "" + ], + "models/staging/stg_orders.sql": [ + "SELECT", + " id AS order_id,", + " customer_id,", + " waffle_type_id,", + " quantity,", + " ordered_at,", + " status", + "FROM __source(\"raw_orders\")", + "" + ], + "models/staging/stg_payments.sql": [ + "SELECT", + " id AS payment_id,", + " order_id,", + " amount_cents,", + " payment_method,", + " paid_at,", + " status AS payment_status", + "FROM __source(\"raw_payments\")", + "" + ], + "tests/fact_orders/test_fact_orders.sql": [ + "WITH __ref__stg_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS status),", + "__ref__stg_payments AS (SELECT", + " 10 AS payment_id,", + " 1 AS order_id,", + " 2850 AS amount_cents,", + " 'card' AS payment_method,", + " CAST('2026-04-01 10:05:00' AS TIMESTAMP) AS paid_at,", + " 'success' AS payment_status),", + "__seed__waffle_types AS (SELECT", + " 2 AS waffle_type_id,", + " 'Liege' AS waffle_name,", + " 'sweet' AS category,", + " 950 AS price_cents),", + "__ref__fact_orders AS (SELECT", + " o.order_id,", + " o.customer_id,", + " o.waffle_type_id,", + " w.waffle_name,", + " w.category AS waffle_category,", + " o.quantity,", + " w.price_cents * o.quantity AS line_total_cents,", + " o.ordered_at,", + " o.status AS order_status,", + " main.is_completed_order(o.status) AS is_completed_order,", + " is_completed_order_py(o.status) AS is_completed_order_py,", + " p.payment_method,", + " p.payment_status,", + " p.amount_cents AS payment_amount_cents", + "FROM __ref__stg_orders o", + "LEFT JOIN __seed__waffle_types w ON o.waffle_type_id = w.waffle_type_id", + "LEFT JOIN __ref__stg_payments p ON o.order_id = p.order_id),", + "__actual__fact_orders AS (SELECT * FROM __ref__fact_orders),", + "__expected__fact_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 'Liege' AS waffle_name,", + " 'sweet' AS waffle_category,", + " 3 AS quantity,", + " 2850 AS line_total_cents,", + " CAST('2026-04-01 10:00:00' AS TIMESTAMP) AS ordered_at,", + " 'completed' AS order_status,", + " TRUE AS is_completed_order,", + " TRUE AS is_completed_order_py,", + " 'card' AS payment_method,", + " 'success' AS payment_status,", + " 2850 AS payment_amount_cents),", + "__assert__line_totals_are_non_negative AS (SELECT *", + " FROM __ref__fact_orders", + " WHERE line_total_cents < 0)", + "SELECT 0 AS step_index, 'fact_orders' AS model_name, (SELECT COUNT(*) FROM __actual__fact_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__fact_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, is_completed_order_py, payment_method, payment_status, payment_amount_cents FROM __actual__fact_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, is_completed_order_py, payment_method, payment_status, payment_amount_cents FROM __expected__fact_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, is_completed_order_py, payment_method, payment_status, payment_amount_cents FROM __expected__fact_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, waffle_name, waffle_category, quantity, line_total_cents, ordered_at, order_status, is_completed_order, is_completed_order_py, payment_method, payment_status, payment_amount_cents FROM __actual__fact_orders) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'assertion line_totals_are_non_negative' AS model_name, (SELECT COUNT(*) FROM __assert__line_totals_are_non_negative) AS actual_count, 0 AS expected_count, (SELECT COUNT(*) FROM __assert__line_totals_are_non_negative) AS unexpected_count, 0 AS missing_count", + "" + ], + "tests/macro calculates_line_total_cents/calculates_line_total_cents.sql": [ + "WITH input_values AS (SELECT 950 AS price_cents, 3 AS quantity),", + "__actual__macro_calculates_line_total_cents AS (SELECT price_cents * quantity AS line_total_cents", + " FROM input_values),", + "__expected__macro_calculates_line_total_cents AS (SELECT 2850 AS line_total_cents)", + "SELECT 0 AS step_index, 'macro calculates_line_total_cents' AS model_name, (SELECT COUNT(*) FROM __actual__macro_calculates_line_total_cents) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_calculates_line_total_cents) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_calculates_line_total_cents EXCEPT SELECT * FROM __expected__macro_calculates_line_total_cents) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_calculates_line_total_cents EXCEPT SELECT * FROM __actual__macro_calculates_line_total_cents) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_orders/test_stg_orders.sql": [ + "WITH __source__raw_orders AS (SELECT", + " 1 AS id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " '2026-04-01 10:00:00' AS ordered_at,", + " 'completed' AS status),", + "__ref__stg_orders AS (SELECT", + " id AS order_id,", + " customer_id,", + " waffle_type_id,", + " quantity,", + " ordered_at,", + " status", + "FROM __source__raw_orders),", + "__actual__stg_orders AS (SELECT * FROM __ref__stg_orders),", + "__expected__stg_orders AS (SELECT", + " 1 AS order_id,", + " 100 AS customer_id,", + " 2 AS waffle_type_id,", + " 3 AS quantity,", + " '2026-04-01 10:00:00' AS ordered_at,", + " 'completed' AS status),", + "__assert__order_ids_are_not_null AS (SELECT *", + " FROM __ref__stg_orders", + " WHERE order_id IS NULL)", + "SELECT 0 AS step_index, 'stg_orders' AS model_name, (SELECT COUNT(*) FROM __actual__stg_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __expected__stg_orders EXCEPT SELECT order_id, customer_id, waffle_type_id, quantity, ordered_at, status FROM __actual__stg_orders) AS __sqlbuild_missing) AS missing_count", + "UNION ALL", + "SELECT 1 AS step_index, 'assertion order_ids_are_not_null' AS model_name, (SELECT COUNT(*) FROM __assert__order_ids_are_not_null) AS actual_count, 0 AS expected_count, (SELECT COUNT(*) FROM __assert__order_ids_are_not_null) AS unexpected_count, 0 AS missing_count", + "" + ], + "tests/table_fn returns_customer_orders/returns_customer_orders.sql": [ + "WITH __actual__table_fn_returns_customer_orders AS (SELECT", + " order_id,", + " order_status,", + " is_completed_order", + " FROM main.customer_orders(1)),", + "__expected__table_fn_returns_customer_orders AS (SELECT 1 AS order_id, 'completed' AS order_status, TRUE AS is_completed_order", + " UNION ALL", + " SELECT 2 AS order_id, 'completed' AS order_status, TRUE AS is_completed_order", + " UNION ALL", + " SELECT 8 AS order_id, 'completed' AS order_status, TRUE AS is_completed_order)", + "SELECT 0 AS step_index, 'table_fn returns_customer_orders' AS model_name, (SELECT COUNT(*) FROM __actual__table_fn_returns_customer_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__table_fn_returns_customer_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__table_fn_returns_customer_orders EXCEPT SELECT * FROM __expected__table_fn_returns_customer_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__table_fn_returns_customer_orders EXCEPT SELECT * FROM __actual__table_fn_returns_customer_orders) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/udf detects_completed_orders/detects_completed_orders.sql": [ + "WITH input_values AS (SELECT 'completed' AS order_status", + " UNION ALL", + " SELECT 'pending' AS order_status),", + "__actual__udf_detects_completed_orders AS (SELECT", + " order_status,", + " main.is_completed_order(order_status) AS is_completed_order", + " FROM input_values),", + "__expected__udf_detects_completed_orders AS (SELECT 'completed' AS order_status, TRUE AS is_completed_order", + " UNION ALL", + " SELECT 'pending' AS order_status, FALSE AS is_completed_order)", + "SELECT 0 AS step_index, 'udf detects_completed_orders' AS model_name, (SELECT COUNT(*) FROM __actual__udf_detects_completed_orders) AS actual_count, (SELECT COUNT(*) FROM __expected__udf_detects_completed_orders) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__udf_detects_completed_orders EXCEPT SELECT * FROM __expected__udf_detects_completed_orders) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__udf_detects_completed_orders EXCEPT SELECT * FROM __actual__udf_detects_completed_orders) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.waffle_shop.customer_status_snapshot": { + "database": null, + "schema": "main", + "name": "customer_status_snapshot", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/intermediate/customer_status_snapshot.sql", + "original_file_path": "models/intermediate/customer_status_snapshot.sql", + "unique_id": "model.waffle_shop.customer_status_snapshot", + "fqn": [ + "waffle_shop", + "models", + "intermediate", + "customer_status_snapshot" + ], + "alias": "customer_status_snapshot", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "intermediate", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "merge", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "customer_id" + ], + "on_schema_change": "sync_all_columns", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "intermediate", + "acceptance" + ], + "description": "Merge-based customer snapshot with timestamp cursor and explicit backfill policies.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.customer_status_snapshot", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.order_status_index": { + "database": null, + "schema": "main", + "name": "order_status_index", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/intermediate/order_status_index.sql", + "original_file_path": "models/intermediate/order_status_index.sql", + "unique_id": "model.waffle_shop.order_status_index", + "fqn": [ + "waffle_shop", + "models", + "intermediate", + "order_status_index" + ], + "alias": "order_status_index", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "intermediate", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "append_new_columns", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "intermediate", + "acceptance" + ], + "description": "Integer-cursor incremental projection over fact orders.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.order_status_index", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.daily_activity_rollup": { + "database": null, + "schema": "main", + "name": "daily_activity_rollup", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_activity_rollup.sql", + "original_file_path": "models/marts/daily_activity_rollup.sql", + "unique_id": "model.waffle_shop.daily_activity_rollup", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_activity_rollup" + ], + "alias": "daily_activity_rollup", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts", + "acceptance" + ], + "description": "Downstream daily microbatch rollup with a wider batch size than its hourly upstream.", + "columns": { + "activity_day": { + "name": "activity_day", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.daily_activity_rollup", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.hourly_order_activity" + ] + } + }, + "model.waffle_shop.daily_order_partitioned": { + "database": null, + "schema": "main", + "name": "daily_order_partitioned", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_order_partitioned.sql", + "original_file_path": "models/marts/daily_order_partitioned.sql", + "unique_id": "model.waffle_shop.daily_order_partitioned", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_order_partitioned" + ], + "alias": "daily_order_partitioned", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "partition_tracked", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Partition-tracked daily order summary using custom materialization.", + "columns": { + "order_date": { + "name": "order_date", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.daily_order_partitioned", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_orders" + ] + } + }, + "model.waffle_shop.daily_revenue": { + "database": null, + "schema": "main", + "name": "daily_revenue", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/daily_revenue.sql", + "original_file_path": "models/marts/daily_revenue.sql", + "unique_id": "model.waffle_shop.daily_revenue", + "fqn": [ + "waffle_shop", + "models", + "marts", + "daily_revenue" + ], + "alias": "daily_revenue", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Daily revenue aggregation.", + "columns": { + "revenue_date": { + "name": "revenue_date", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.daily_revenue", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.dim_customers": { + "database": null, + "schema": "main", + "name": "dim_customers", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/dim_customers.sql", + "original_file_path": "models/marts/dim_customers.sql", + "unique_id": "model.waffle_shop.dim_customers", + "fqn": [ + "waffle_shop", + "models", + "marts", + "dim_customers" + ], + "alias": "dim_customers", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Customer dimension with lifetime metrics.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.dim_customers", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_customers", + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.fact_orders": { + "database": null, + "schema": "main", + "name": "fact_orders", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/fact_orders.sql", + "original_file_path": "models/marts/fact_orders.sql", + "unique_id": "model.waffle_shop.fact_orders", + "fqn": [ + "waffle_shop", + "models", + "marts", + "fact_orders" + ], + "alias": "fact_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Order fact table with waffle and payment details.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.fact_orders", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.is_completed_order", + "model.waffle_shop.is_completed_order_py", + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.hourly_activity_with_daily_context": { + "database": null, + "schema": "main", + "name": "hourly_activity_with_daily_context", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/hourly_activity_with_daily_context.sql", + "original_file_path": "models/marts/hourly_activity_with_daily_context.sql", + "unique_id": "model.waffle_shop.hourly_activity_with_daily_context", + "fqn": [ + "waffle_shop", + "models", + "marts", + "hourly_activity_with_daily_context" + ], + "alias": "hourly_activity_with_daily_context", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts", + "acceptance" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts", + "acceptance" + ], + "description": "Hourly downstream microbatch model that depends on a coarser-grain daily upstream.", + "columns": { + "activity_hour": { + "name": "activity_hour", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.hourly_activity_with_daily_context", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.hourly_order_activity", + "model.waffle_shop.daily_activity_rollup" + ] + } + }, + "model.waffle_shop.hourly_order_activity": { + "database": null, + "schema": "main", + "name": "hourly_order_activity", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/hourly_order_activity.sql", + "original_file_path": "models/marts/hourly_order_activity.sql", + "unique_id": "model.waffle_shop.hourly_order_activity", + "fqn": [ + "waffle_shop", + "models", + "marts", + "hourly_order_activity" + ], + "alias": "hourly_order_activity", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts" + ], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts" + ], + "description": "Hourly order activity aggregated via microbatch incremental.", + "columns": { + "activity_hour": { + "name": "activity_hour", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.hourly_order_activity", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.fact_orders" + ] + } + }, + "model.waffle_shop.scenario_order_prices": { + "database": null, + "schema": "main", + "name": "scenario_order_prices", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/marts/scenario_order_prices.sql", + "original_file_path": "models/marts/scenario_order_prices.sql", + "unique_id": "model.waffle_shop.scenario_order_prices", + "fqn": [ + "waffle_shop", + "models", + "marts", + "scenario_order_prices" + ], + "alias": "scenario_order_prices", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "marts", + "scenario" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "marts", + "scenario" + ], + "description": "Small model used by scenario CLI e2e retain coverage.", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.scenario_order_prices", + "depends_on": { + "macros": [], + "nodes": [ + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ] + } + }, + "model.waffle_shop.stg_customers": { + "database": null, + "schema": "main", + "name": "stg_customers", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_customers.sql", + "original_file_path": "models/staging/stg_customers.sql", + "unique_id": "model.waffle_shop.stg_customers", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_customers" + ], + "alias": "stg_customers", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned customer records.", + "columns": { + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "email": { + "name": "email", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_customers", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw_customers" + ] + } + }, + "model.waffle_shop.stg_orders": { + "database": null, + "schema": "main", + "name": "stg_orders", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_orders.sql", + "original_file_path": "models/staging/stg_orders.sql", + "unique_id": "model.waffle_shop.stg_orders", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_orders" + ], + "alias": "stg_orders", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned order records.", + "columns": { + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_orders", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw_orders" + ] + } + }, + "model.waffle_shop.stg_payments": { + "database": null, + "schema": "main", + "name": "stg_payments", + "resource_type": "model", + "package_name": "waffle_shop", + "path": "models/staging/stg_payments.sql", + "original_file_path": "models/staging/stg_payments.sql", + "unique_id": "model.waffle_shop.stg_payments", + "fqn": [ + "waffle_shop", + "models", + "staging", + "stg_payments" + ], + "alias": "stg_payments", + "config": { + "enabled": true, + "alias": null, + "schema": null, + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Cleaned payment records.", + "columns": { + "payment_id": { + "name": "payment_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "order_id": { + "name": "order_id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_payments", + "depends_on": { + "macros": [], + "nodes": [ + "source.waffle_shop.raw_payments" + ] + } + }, + "seed.waffle_shop.waffle_types": { + "database": null, + "schema": "main", + "name": "waffle_types", + "resource_type": "seed", + "package_name": "waffle_shop", + "path": "seeds/waffle_types.csv", + "original_file_path": "seeds/waffle_types.csv", + "unique_id": "seed.waffle_shop.waffle_types", + "fqn": [ + "waffle_shop", + "seeds", + "waffle_types" + ], + "alias": "waffle_types", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Waffle menu items with pricing.", + "columns": { + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_name": { + "name": "waffle_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "category": { + "name": "category", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "price_cents": { + "name": "price_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.waffle_types", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.waffle_shop.raw_customers": { + "database": null, + "schema": "", + "name": "raw_customers", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw_customers", + "fqn": [ + "waffle_shop", + "raw_customers" + ], + "source_name": "raw_customers", + "source_description": "", + "loader": "", + "identifier": "raw_customers", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_customers.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "first_name": { + "name": "first_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "last_name": { + "name": "last_name", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "email": { + "name": "email", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_customers", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.waffle_shop.raw_orders": { + "database": null, + "schema": "", + "name": "raw_orders", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw_orders", + "fqn": [ + "waffle_shop", + "raw_orders" + ], + "source_name": "raw_orders", + "source_description": "", + "loader": "", + "identifier": "raw_orders", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_orders.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "customer_id": { + "name": "customer_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "waffle_type_id": { + "name": "waffle_type_id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "quantity": { + "name": "quantity", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "ordered_at": { + "name": "ordered_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "raw_orders", + "auto_load": false, + "write_strategy": "delete_insert", + "cursor_column": "ordered_at" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.waffle_shop.raw_payments": { + "database": null, + "schema": "", + "name": "raw_payments", + "resource_type": "source", + "package_name": "waffle_shop", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.waffle_shop.raw_payments", + "fqn": [ + "waffle_shop", + "raw_payments" + ], + "source_name": "raw_payments", + "source_description": "", + "loader": "", + "identifier": "raw_payments", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Test source raw_payments.", + "columns": { + "amount_cents": { + "name": "amount_cents", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.waffle_shop.line_total_cents": { + "name": "line_total_cents", + "resource_type": "macro", + "package_name": "waffle_shop", + "path": "macros/currency.py", + "original_file_path": "macros/currency.py", + "unique_id": "macro.waffle_shop.line_total_cents", + "macro_sql": "\"\"\"Currency formatting macros.\"\"\"\n\n\ndef line_total_cents(price_cents: str, quantity: str) -> str:\n \"\"\"Calculate line total cents from a unit price and quantity.\"\"\"\n return f\"{price_cents} * {quantity}\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.waffle_shop.timestamp_trunc": { + "name": "timestamp_trunc", + "resource_type": "macro", + "package_name": "waffle_shop", + "path": "models/marts/_macros/time.py", + "original_file_path": "models/marts/_macros/time.py", + "unique_id": "macro.waffle_shop.timestamp_trunc", + "macro_sql": "\"\"\"Time expression macros.\"\"\"\n\nfrom sqlbuild.compiler.compile.models import MacroContext\n\n\ndef timestamp_trunc(ctx: MacroContext, grain: str, expression: str) -> str:\n \"\"\"Render timestamp truncation for the active adapter.\"\"\"\n\n if ctx.adapter_name == \"bigquery\":\n return f\"TIMESTAMP_TRUNC({expression}, {grain.upper()})\"\n return f\"DATE_TRUNC('{grain}', {expression})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.waffle_shop.customer_status_snapshot": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.order_status_index": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.daily_activity_rollup": [ + "model.waffle_shop.hourly_order_activity" + ], + "model.waffle_shop.daily_order_partitioned": [ + "model.waffle_shop.stg_orders" + ], + "model.waffle_shop.daily_revenue": [ + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.dim_customers": [ + "model.waffle_shop.stg_customers", + "model.waffle_shop.stg_orders", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.fact_orders": [ + "model.waffle_shop.is_completed_order", + "model.waffle_shop.is_completed_order_py", + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.hourly_activity_with_daily_context": [ + "model.waffle_shop.hourly_order_activity", + "model.waffle_shop.daily_activity_rollup" + ], + "model.waffle_shop.hourly_order_activity": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.scenario_order_prices": [ + "model.waffle_shop.stg_orders", + "seed.waffle_shop.waffle_types", + "model.waffle_shop.stg_payments" + ], + "model.waffle_shop.stg_customers": [ + "source.waffle_shop.raw_customers" + ], + "model.waffle_shop.stg_orders": [ + "source.waffle_shop.raw_orders" + ], + "model.waffle_shop.stg_payments": [ + "source.waffle_shop.raw_payments" + ], + "source.waffle_shop.raw_customers": [], + "source.waffle_shop.raw_orders": [], + "source.waffle_shop.raw_payments": [], + "seed.waffle_shop.waffle_types": [], + "model.waffle_shop.customer_orders": [ + "model.waffle_shop.fact_orders" + ], + "model.waffle_shop.is_completed_order": [], + "model.waffle_shop.is_completed_order_py": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/0-postgres.json b/tests/goldens/compiler/seed/0-postgres.json new file mode 100644 index 0000000000..13f05d651d --- /dev/null +++ b/tests/goldens/compiler/seed/0-postgres.json @@ -0,0 +1,2906 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/checked_stg_fulfillment_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_fulfillment_1/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_fulfillment_1/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_fulfillment_1\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/fulfillment_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"fulfillment_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_2/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_2\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_fulfillment_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_sales_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_sales_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_sales_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_sales_1\")", + "WHERE id IS NULL", + "" + ], + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE FUNCTION analytics.scaled_amount(p_amount DOUBLE, p_factor INTEGER)", + "RETURNS DOUBLE", + "LANGUAGE SQL AS $$", + "p_amount * p_factor", + "$$", + "" + ], + "functions/sql/table_fn__amount_bands.sql": [ + "CREATE OR REPLACE FUNCTION analytics.table_fn__amount_bands(p_floor DOUBLE)", + "RETURNS TABLE (id INTEGER, band VARCHAR)", + "LANGUAGE SQL AS $$", + "SELECT CAST(id AS INTEGER) AS id,", + " CASE WHEN amount > p_floor THEN 'high' ELSE 'low' END AS band", + "FROM __ref(\"stg_fulfillment_0\")", + "$$", + "" + ], + "models/analysis/banded_amounts.sql": [ + "SELECT bands.id, bands.band", + "FROM __table_fn(\"table_fn__amount_bands\")(2.5) AS bands", + "" + ], + "models/analysis/chain_1_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"contracted_stg_sales_0\")", + "" + ], + "models/analysis/chain_2_stg_sales_0.sql": [ + "SELECT id, UPPER(label) AS label, amount", + "FROM __ref(\"chain_1_stg_sales_0\")", + "" + ], + "models/analysis/chain_3_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"chain_2_stg_sales_0\")", + "" + ], + "models/analysis/checked_stg_fulfillment_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/analysis/combined_stg_fulfillment_0.sql": [ + "WITH recent AS (", + " SELECT id, created_at FROM __ref(\"stg_fulfillment_0\") WHERE amount > 0", + "),", + "older AS (", + " SELECT id, created_at FROM __ref(\"stg_sales_1\")", + ")", + "SELECT id, created_at FROM recent", + "UNION ALL", + "SELECT id, created_at FROM older", + "" + ], + "models/analysis/contracted_stg_sales_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR(19)) AS label,", + " amount", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/every_open_event.sql": [ + "SELECT *", + "FROM __source(\"open_events\")", + "" + ], + "models/analysis/every_raw_events_0.sql": [ + "SELECT *", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/every_stg_fulfillment_0.sql": [ + "SELECT *", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/passed_stg_fulfillment_0.sql": [ + "WITH passthrough AS (", + " SELECT id, created_at FROM __ref(\"stg_fulfillment_0\")", + ")", + "SELECT id, created_at", + "FROM passthrough", + "" + ], + "models/analysis/regional_stg_fulfillment_1.sql": [ + "SELECT id, amount, 'east' AS region", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/analysis/scaled_stg_fulfillment_0.sql": [ + "SELECT id, __udf(\"scaled_amount\")(amount, 2) AS scaled_amount", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/typed_stg_fulfillment_0.sql": [ + "SELECT id, amount * 2 AS doubled_amount, CAST(status AS VARCHAR) AS status_text,", + " created_at, NULL AS missing_note", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/unanalysed_stg_fulfillment_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/fulfillment/marts/fulfillment_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j2.label AS lookup_label_2", + "FROM __ref(\"stg_fulfillment_0\") t", + "LEFT JOIN __ref(\"stg_sales_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/fulfillment/marts/fulfillment_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_fulfillment_0\") t", + "" + ], + "models/fulfillment/marts/fulfillment_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j1.label AS lookup_label_1,", + " 'Zürich – depot' AS site_label", + "FROM __ref(\"stg_fulfillment_1\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "" + ], + "models/fulfillment/staging/stg_fulfillment_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount", + "FROM __source(\"raw_events_0\") t", + "WHERE t.status <> 'expédié'", + "" + ], + "models/sales/marts/sales_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_1\") j1 ON t.id = j1.id", + "" + ], + "models/sales/marts/sales_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "WHERE t.status <> '取消'", + "" + ], + "models/sales/marts/sales_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " j2.label AS lookup_label_2", + "FROM __ref(\"stg_sales_1\") t", + "LEFT JOIN __ref(\"stg_fulfillment_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/sales/staging/stg_sales_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * '1e-07' AS threshold_2_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/sales/staging/stg_sales_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "tests/regional_stg_fulfillment_1/test_regional_stg_fulfillment_1.sql": [ + "WITH __ref__stg_fulfillment_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_fulfillment_1 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_fulfillment_1),", + "__actual__regional_stg_fulfillment_1 AS (SELECT * FROM __ref__regional_stg_fulfillment_1),", + "__expected__regional_stg_fulfillment_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_fulfillment_1' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_fulfillment_1) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_fulfillment_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_fulfillment_1 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_fulfillment_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_fulfillment_1 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_fulfillment_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_fulfillment_0/test_stg_fulfillment_0.sql": [ + "WITH __source__raw_events_1 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_fulfillment_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source__raw_events_1 t),", + "__actual__stg_fulfillment_0 AS (SELECT * FROM __ref__stg_fulfillment_0),", + "__expected__stg_fulfillment_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_fulfillment_0 EXCEPT SELECT id, status FROM __expected__stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_fulfillment_0 EXCEPT SELECT id, status FROM __actual__stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_0.banded_amounts": { + "database": null, + "schema": "analytics", + "name": "banded_amounts", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/banded_amounts.sql", + "original_file_path": "models/analysis/banded_amounts.sql", + "unique_id": "model.generated_0.banded_amounts", + "fqn": [ + "generated_0", + "models", + "analysis", + "banded_amounts" + ], + "alias": "banded_amounts", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amount bands from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.banded_amounts", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.table_fn__amount_bands" + ] + } + }, + "model.generated_0.chain_1_stg_sales_0": { + "database": null, + "schema": "analytics", + "name": "chain_1_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_1_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_1_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_1_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_1_stg_sales_0" + ], + "alias": "chain_1_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 1 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.chain_1_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.contracted_stg_sales_0" + ] + } + }, + "model.generated_0.chain_2_stg_sales_0": { + "database": null, + "schema": "analytics", + "name": "chain_2_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_2_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_2_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_2_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_2_stg_sales_0" + ], + "alias": "chain_2_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 2 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.chain_2_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.chain_1_stg_sales_0" + ] + } + }, + "model.generated_0.chain_3_stg_sales_0": { + "database": null, + "schema": "analytics", + "name": "chain_3_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_3_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_3_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_3_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_3_stg_sales_0" + ], + "alias": "chain_3_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 3 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.chain_3_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.chain_2_stg_sales_0" + ] + } + }, + "model.generated_0.checked_stg_fulfillment_1": { + "database": null, + "schema": "analytics", + "name": "checked_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/checked_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/checked_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.checked_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "analysis", + "checked_stg_fulfillment_1" + ], + "alias": "checked_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_fulfillment_1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.checked_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.combined_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "combined_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/combined_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/combined_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.combined_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "combined_stg_fulfillment_0" + ], + "alias": "combined_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Recent and older rows of stg_fulfillment_0 and stg_sales_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.combined_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_1" + ] + } + }, + "model.generated_0.contracted_stg_sales_0": { + "database": null, + "schema": "analytics", + "name": "contracted_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/contracted_stg_sales_0.sql", + "original_file_path": "models/analysis/contracted_stg_sales_0.sql", + "unique_id": "model.generated_0.contracted_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "contracted_stg_sales_0" + ], + "alias": "contracted_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted copy of raw_events_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR(19)", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.contracted_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.every_open_event": { + "database": null, + "schema": "analytics", + "name": "every_open_event", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_open_event.sql", + "original_file_path": "models/analysis/every_open_event.sql", + "unique_id": "model.generated_0.every_open_event", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_open_event" + ], + "alias": "every_open_event", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of an open source", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.every_open_event", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.open_events" + ] + } + }, + "model.generated_0.every_raw_events_0": { + "database": null, + "schema": "analytics", + "name": "every_raw_events_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_raw_events_0.sql", + "original_file_path": "models/analysis/every_raw_events_0.sql", + "unique_id": "model.generated_0.every_raw_events_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_raw_events_0" + ], + "alias": "every_raw_events_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of raw_events_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.every_raw_events_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.every_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "every_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/every_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.every_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_stg_fulfillment_0" + ], + "alias": "every_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.every_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.passed_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "passed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/passed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/passed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.passed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "passed_stg_fulfillment_0" + ], + "alias": "passed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Columns of stg_fulfillment_0 passed through a CTE", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.passed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.regional_stg_fulfillment_1": { + "database": null, + "schema": "analytics", + "name": "regional_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/regional_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/regional_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.regional_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "analysis", + "regional_stg_fulfillment_1" + ], + "alias": "regional_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.regional_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.scaled_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "scaled_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/scaled_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/scaled_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.scaled_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "scaled_stg_fulfillment_0" + ], + "alias": "scaled_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Scaled amounts of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.scaled_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.scaled_amount", + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.typed_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "typed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/typed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/typed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.typed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "typed_stg_fulfillment_0" + ], + "alias": "typed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Typed and untyped outputs of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.typed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.unanalysed_stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "unanalysed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/unanalysed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/unanalysed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.unanalysed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "unanalysed_stg_fulfillment_0" + ], + "alias": "unanalysed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_fulfillment_0 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.unanalysed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_0": { + "database": null, + "schema": "analytics", + "name": "fulfillment_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "unique_id": "model.generated_0.fulfillment_summary_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_0" + ], + "alias": "fulfillment_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.fulfillment_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.fulfillment_summary_1": { + "database": null, + "schema": "analytics", + "name": "fulfillment_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "unique_id": "model.generated_0.fulfillment_summary_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_1" + ], + "alias": "fulfillment_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'analytics.fulfillment_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'analytics.fulfillment_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'analytics.fulfillment_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'analytics.fulfillment_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.fulfillment_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_2": { + "database": null, + "schema": "analytics", + "name": "fulfillment_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "unique_id": "model.generated_0.fulfillment_summary_2", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_2" + ], + "alias": "fulfillment_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'analytics.fulfillment_summary_2' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'analytics.fulfillment_summary_2' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 2 (naïve résumé)", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'analytics.fulfillment_summary_2' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "café ☕ counter" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'analytics.fulfillment_summary_2' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.fulfillment_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.stg_fulfillment_0": { + "database": null, + "schema": "analytics", + "name": "stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "unique_id": "model.generated_0.stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_0" + ], + "alias": "stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "model.generated_0.stg_fulfillment_1": { + "database": null, + "schema": "analytics", + "name": "stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "unique_id": "model.generated_0.stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_1" + ], + "alias": "stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.sales_summary_0": { + "database": null, + "schema": "analytics", + "name": "sales_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_0.sql", + "original_file_path": "models/sales/marts/sales_summary_0.sql", + "unique_id": "model.generated_0.sales_summary_0", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_0" + ], + "alias": "sales_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.sales_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.sales_summary_1": { + "database": null, + "schema": "analytics", + "name": "sales_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_1.sql", + "original_file_path": "models/sales/marts/sales_summary_1.sql", + "unique_id": "model.generated_0.sales_summary_1", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_1" + ], + "alias": "sales_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'analytics.sales_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'analytics.sales_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'analytics.sales_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "東京 warehouse" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'analytics.sales_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.sales_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.sales_summary_2": { + "database": null, + "schema": "analytics", + "name": "sales_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_2.sql", + "original_file_path": "models/sales/marts/sales_summary_2.sql", + "unique_id": "model.generated_0.sales_summary_2", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_2" + ], + "alias": "sales_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 2 (Ελληνικά orders)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.sales_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.stg_sales_0": { + "database": null, + "schema": "analytics", + "name": "stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_0.sql", + "original_file_path": "models/sales/staging/stg_sales_0.sql", + "unique_id": "model.generated_0.stg_sales_0", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_0" + ], + "alias": "stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.stg_sales_1": { + "database": null, + "schema": "analytics", + "name": "stg_sales_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_1.sql", + "original_file_path": "models/sales/staging/stg_sales_1.sql", + "unique_id": "model.generated_0.stg_sales_1", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_1" + ], + "alias": "stg_sales_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.stg_sales_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "seed.generated_0.lookup_0": { + "database": null, + "schema": "analytics", + "name": "lookup_0", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_0.csv", + "original_file_path": "seeds/lookup_0.csv", + "unique_id": "seed.generated_0.lookup_0", + "fqn": [ + "generated_0", + "seeds", + "lookup_0" + ], + "alias": "lookup_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.lookup_0", + "root_path": null, + "depends_on": { + "macros": [] + } + }, + "seed.generated_0.lookup_1": { + "database": null, + "schema": "analytics", + "name": "lookup_1", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_1.csv", + "original_file_path": "seeds/lookup_1.csv", + "unique_id": "seed.generated_0.lookup_1", + "fqn": [ + "generated_0", + "seeds", + "lookup_1" + ], + "alias": "lookup_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "analytics.lookup_1", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.generated_0.open_events": { + "database": null, + "schema": "", + "name": "open_events", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/open.yml", + "original_file_path": "sources/open.yml", + "unique_id": "source.generated_0.open_events", + "fqn": [ + "generated_0", + "open_events" + ], + "source_name": "open_events", + "source_description": "", + "loader": "", + "identifier": "open_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Events whose columns are only known to the warehouse.", + "columns": {}, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_0", + "fqn": [ + "generated_0", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_1", + "fqn": [ + "generated_0", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_0.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_0.adjust_0_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_0_round": { + "name": "adjust_0_round", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0_round", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_2.py", + "original_file_path": "macros/adjust_2.py", + "unique_id": "macro.generated_0.adjust_2", + "macro_sql": "def adjust_2(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_0.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'east'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_0.adjust_1", + "macro_sql": "import os\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Tag an amount with the deployment region.\"\"\"\n region = os.environ.get(\"SQB_DIFFERENTIAL_REGION\", \"east\")\n return f\"({expression} + LENGTH('{region}'))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/fulfillment/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_0__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_0__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_0.banded_amounts": [ + "model.generated_0.table_fn__amount_bands" + ], + "model.generated_0.chain_1_stg_sales_0": [ + "model.generated_0.contracted_stg_sales_0" + ], + "model.generated_0.chain_2_stg_sales_0": [ + "model.generated_0.chain_1_stg_sales_0" + ], + "model.generated_0.chain_3_stg_sales_0": [ + "model.generated_0.chain_2_stg_sales_0" + ], + "model.generated_0.checked_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.combined_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_1" + ], + "model.generated_0.contracted_stg_sales_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.every_open_event": [ + "source.generated_0.open_events" + ], + "model.generated_0.every_raw_events_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.every_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.passed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.regional_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.scaled_stg_fulfillment_0": [ + "model.generated_0.scaled_amount", + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.typed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.unanalysed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_0": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.fulfillment_summary_1": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_2": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ], + "model.generated_0.stg_fulfillment_0": [ + "source.generated_0.raw_events_1" + ], + "model.generated_0.stg_fulfillment_1": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.sales_summary_0": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.sales_summary_1": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ], + "model.generated_0.sales_summary_2": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.stg_sales_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.stg_sales_1": [ + "source.generated_0.raw_events_1" + ], + "source.generated_0.open_events": [], + "source.generated_0.raw_events_0": [], + "source.generated_0.raw_events_1": [], + "seed.generated_0.lookup_0": [], + "seed.generated_0.lookup_1": [], + "model.generated_0.scaled_amount": [], + "model.generated_0.table_fn__amount_bands": [ + "model.generated_0.stg_fulfillment_0" + ] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/0-snowflake.json b/tests/goldens/compiler/seed/0-snowflake.json new file mode 100644 index 0000000000..86d39efb09 --- /dev/null +++ b/tests/goldens/compiler/seed/0-snowflake.json @@ -0,0 +1,2907 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/checked_stg_fulfillment_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_fulfillment_1/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_fulfillment_1/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_fulfillment_1\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_fulfillment_1\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/fulfillment_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"fulfillment_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_2/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_2\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_fulfillment_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_sales_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_sales_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_sales_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_sales_1\")", + "WHERE id IS NULL", + "" + ], + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE FUNCTION GENERATED.analytics.scaled_amount(p_amount DOUBLE, p_factor INTEGER)", + "RETURNS DOUBLE", + "LANGUAGE SQL", + "AS $$", + "p_amount * p_factor", + "$$", + "" + ], + "functions/sql/table_fn__amount_bands.sql": [ + "CREATE OR REPLACE FUNCTION GENERATED.analytics.table_fn__amount_bands(p_floor DOUBLE)", + "RETURNS TABLE (id INTEGER, band VARCHAR)", + "AS $$", + "SELECT CAST(id AS INTEGER) AS id,", + " CASE WHEN amount > p_floor THEN 'high' ELSE 'low' END AS band", + "FROM __ref(\"stg_fulfillment_0\")", + "$$", + "" + ], + "models/analysis/banded_amounts.sql": [ + "SELECT bands.id, bands.band", + "FROM __table_fn(\"table_fn__amount_bands\")(2.5) AS bands", + "" + ], + "models/analysis/chain_1_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"contracted_stg_sales_0\")", + "" + ], + "models/analysis/chain_2_stg_sales_0.sql": [ + "SELECT id, UPPER(label) AS label, amount", + "FROM __ref(\"chain_1_stg_sales_0\")", + "" + ], + "models/analysis/chain_3_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"chain_2_stg_sales_0\")", + "" + ], + "models/analysis/checked_stg_fulfillment_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/analysis/combined_stg_fulfillment_0.sql": [ + "WITH recent AS (", + " SELECT id, created_at FROM __ref(\"stg_fulfillment_0\") WHERE amount > 0", + "),", + "older AS (", + " SELECT id, created_at FROM __ref(\"stg_sales_1\")", + ")", + "SELECT id, created_at FROM recent", + "UNION ALL", + "SELECT id, created_at FROM older", + "" + ], + "models/analysis/contracted_stg_sales_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR(19)) AS label,", + " amount", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/every_open_event.sql": [ + "SELECT *", + "FROM __source(\"open_events\")", + "" + ], + "models/analysis/every_raw_events_0.sql": [ + "SELECT *", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/every_stg_fulfillment_0.sql": [ + "SELECT *", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/passed_stg_fulfillment_0.sql": [ + "WITH passthrough AS (", + " SELECT id, created_at FROM __ref(\"stg_fulfillment_0\")", + ")", + "SELECT id, created_at", + "FROM passthrough", + "" + ], + "models/analysis/regional_stg_fulfillment_1.sql": [ + "SELECT id, amount, 'east' AS region", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/analysis/scaled_stg_fulfillment_0.sql": [ + "SELECT id, __udf(\"scaled_amount\")(amount, 2) AS scaled_amount", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/typed_stg_fulfillment_0.sql": [ + "SELECT id, amount * 2 AS doubled_amount, CAST(status AS VARCHAR) AS status_text,", + " created_at, NULL AS missing_note", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/unanalysed_stg_fulfillment_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/fulfillment/marts/fulfillment_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j2.label AS lookup_label_2", + "FROM __ref(\"stg_fulfillment_0\") t", + "LEFT JOIN __ref(\"stg_sales_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/fulfillment/marts/fulfillment_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_fulfillment_0\") t", + "" + ], + "models/fulfillment/marts/fulfillment_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j1.label AS lookup_label_1,", + " 'Zürich – depot' AS site_label", + "FROM __ref(\"stg_fulfillment_1\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "" + ], + "models/fulfillment/staging/stg_fulfillment_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount", + "FROM __source(\"raw_events_0\") t", + "WHERE t.status <> 'expédié'", + "" + ], + "models/sales/marts/sales_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_1\") j1 ON t.id = j1.id", + "" + ], + "models/sales/marts/sales_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 1e-07)) AS adjust_2_amount,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "WHERE t.status <> '取消'", + "" + ], + "models/sales/marts/sales_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " j2.label AS lookup_label_2", + "FROM __ref(\"stg_sales_1\") t", + "LEFT JOIN __ref(\"stg_fulfillment_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/sales/staging/stg_sales_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * '1e-07' AS threshold_2_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/sales/staging/stg_sales_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "tests/regional_stg_fulfillment_1/test_regional_stg_fulfillment_1.sql": [ + "WITH __ref__stg_fulfillment_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_fulfillment_1 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_fulfillment_1),", + "__actual__regional_stg_fulfillment_1 AS (SELECT * FROM __ref__regional_stg_fulfillment_1),", + "__expected__regional_stg_fulfillment_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_fulfillment_1' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_fulfillment_1) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_fulfillment_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_fulfillment_1 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_fulfillment_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_fulfillment_1 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_fulfillment_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_fulfillment_0/test_stg_fulfillment_0.sql": [ + "WITH __source__raw_events_1 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_fulfillment_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source__raw_events_1 t),", + "__actual__stg_fulfillment_0 AS (SELECT * FROM __ref__stg_fulfillment_0),", + "__expected__stg_fulfillment_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_fulfillment_0 EXCEPT SELECT id, status FROM __expected__stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_fulfillment_0 EXCEPT SELECT id, status FROM __actual__stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_0.banded_amounts": { + "database": "GENERATED", + "schema": "analytics", + "name": "banded_amounts", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/banded_amounts.sql", + "original_file_path": "models/analysis/banded_amounts.sql", + "unique_id": "model.generated_0.banded_amounts", + "fqn": [ + "generated_0", + "models", + "analysis", + "banded_amounts" + ], + "alias": "banded_amounts", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amount bands from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.banded_amounts", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.table_fn__amount_bands" + ] + } + }, + "model.generated_0.chain_1_stg_sales_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "chain_1_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_1_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_1_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_1_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_1_stg_sales_0" + ], + "alias": "chain_1_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 1 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.chain_1_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.contracted_stg_sales_0" + ] + } + }, + "model.generated_0.chain_2_stg_sales_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "chain_2_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_2_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_2_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_2_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_2_stg_sales_0" + ], + "alias": "chain_2_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 2 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.chain_2_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.chain_1_stg_sales_0" + ] + } + }, + "model.generated_0.chain_3_stg_sales_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "chain_3_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/chain_3_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_3_stg_sales_0.sql", + "unique_id": "model.generated_0.chain_3_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "chain_3_stg_sales_0" + ], + "alias": "chain_3_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 3 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.chain_3_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.chain_2_stg_sales_0" + ] + } + }, + "model.generated_0.checked_stg_fulfillment_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "checked_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/checked_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/checked_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.checked_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "analysis", + "checked_stg_fulfillment_1" + ], + "alias": "checked_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_fulfillment_1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.checked_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.combined_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "combined_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/combined_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/combined_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.combined_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "combined_stg_fulfillment_0" + ], + "alias": "combined_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Recent and older rows of stg_fulfillment_0 and stg_sales_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.combined_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_1" + ] + } + }, + "model.generated_0.contracted_stg_sales_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "contracted_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/contracted_stg_sales_0.sql", + "original_file_path": "models/analysis/contracted_stg_sales_0.sql", + "unique_id": "model.generated_0.contracted_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "contracted_stg_sales_0" + ], + "alias": "contracted_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted copy of raw_events_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR(19)", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.contracted_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.every_open_event": { + "database": "GENERATED", + "schema": "analytics", + "name": "every_open_event", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_open_event.sql", + "original_file_path": "models/analysis/every_open_event.sql", + "unique_id": "model.generated_0.every_open_event", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_open_event" + ], + "alias": "every_open_event", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of an open source", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.every_open_event", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.open_events" + ] + } + }, + "model.generated_0.every_raw_events_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "every_raw_events_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_raw_events_0.sql", + "original_file_path": "models/analysis/every_raw_events_0.sql", + "unique_id": "model.generated_0.every_raw_events_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_raw_events_0" + ], + "alias": "every_raw_events_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of raw_events_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.every_raw_events_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.every_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "every_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/every_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/every_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.every_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "every_stg_fulfillment_0" + ], + "alias": "every_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.every_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.passed_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "passed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/passed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/passed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.passed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "passed_stg_fulfillment_0" + ], + "alias": "passed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Columns of stg_fulfillment_0 passed through a CTE", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.passed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.regional_stg_fulfillment_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "regional_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/regional_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/regional_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.regional_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "analysis", + "regional_stg_fulfillment_1" + ], + "alias": "regional_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.regional_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.scaled_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "scaled_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/scaled_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/scaled_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.scaled_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "scaled_stg_fulfillment_0" + ], + "alias": "scaled_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Scaled amounts of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.scaled_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.scaled_amount", + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.typed_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "typed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/typed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/typed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.typed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "typed_stg_fulfillment_0" + ], + "alias": "typed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Typed and untyped outputs of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.typed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.unanalysed_stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "unanalysed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/unanalysed_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/unanalysed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.unanalysed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "unanalysed_stg_fulfillment_0" + ], + "alias": "unanalysed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_fulfillment_0 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.unanalysed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "fulfillment_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "unique_id": "model.generated_0.fulfillment_summary_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_0" + ], + "alias": "fulfillment_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.fulfillment_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.fulfillment_summary_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "fulfillment_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "unique_id": "model.generated_0.fulfillment_summary_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_1" + ], + "alias": "fulfillment_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'GENERATED.analytics.fulfillment_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'GENERATED.analytics.fulfillment_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.fulfillment_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.fulfillment_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.fulfillment_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_2": { + "database": "GENERATED", + "schema": "analytics", + "name": "fulfillment_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "unique_id": "model.generated_0.fulfillment_summary_2", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_2" + ], + "alias": "fulfillment_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'GENERATED.analytics.fulfillment_summary_2' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'GENERATED.analytics.fulfillment_summary_2' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 2 (naïve résumé)", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.fulfillment_summary_2' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "café ☕ counter" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.fulfillment_summary_2' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.fulfillment_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.stg_fulfillment_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "unique_id": "model.generated_0.stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_0" + ], + "alias": "stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "model.generated_0.stg_fulfillment_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "unique_id": "model.generated_0.stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_1" + ], + "alias": "stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.sales_summary_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "sales_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_0.sql", + "original_file_path": "models/sales/marts/sales_summary_0.sql", + "unique_id": "model.generated_0.sales_summary_0", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_0" + ], + "alias": "sales_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.sales_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.sales_summary_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "sales_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_1.sql", + "original_file_path": "models/sales/marts/sales_summary_1.sql", + "unique_id": "model.generated_0.sales_summary_1", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_1" + ], + "alias": "sales_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'GENERATED.analytics.sales_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'GENERATED.analytics.sales_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.sales_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "東京 warehouse" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'GENERATED.analytics.sales_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.sales_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.sales_summary_2": { + "database": "GENERATED", + "schema": "analytics", + "name": "sales_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_2.sql", + "original_file_path": "models/sales/marts/sales_summary_2.sql", + "unique_id": "model.generated_0.sales_summary_2", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_2" + ], + "alias": "sales_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 2 (Ελληνικά orders)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.sales_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.stg_sales_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_0.sql", + "original_file_path": "models/sales/staging/stg_sales_0.sql", + "unique_id": "model.generated_0.stg_sales_0", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_0" + ], + "alias": "stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.stg_sales_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "stg_sales_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_1.sql", + "original_file_path": "models/sales/staging/stg_sales_1.sql", + "unique_id": "model.generated_0.stg_sales_1", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_1" + ], + "alias": "stg_sales_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.stg_sales_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "seed.generated_0.lookup_0": { + "database": "GENERATED", + "schema": "analytics", + "name": "lookup_0", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_0.csv", + "original_file_path": "seeds/lookup_0.csv", + "unique_id": "seed.generated_0.lookup_0", + "fqn": [ + "generated_0", + "seeds", + "lookup_0" + ], + "alias": "lookup_0", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.lookup_0", + "root_path": null, + "depends_on": { + "macros": [] + } + }, + "seed.generated_0.lookup_1": { + "database": "GENERATED", + "schema": "analytics", + "name": "lookup_1", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_1.csv", + "original_file_path": "seeds/lookup_1.csv", + "unique_id": "seed.generated_0.lookup_1", + "fqn": [ + "generated_0", + "seeds", + "lookup_1" + ], + "alias": "lookup_1", + "config": { + "enabled": true, + "alias": null, + "schema": "analytics", + "database": "GENERATED", + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "GENERATED.analytics.lookup_1", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.generated_0.open_events": { + "database": null, + "schema": "", + "name": "open_events", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/open.yml", + "original_file_path": "sources/open.yml", + "unique_id": "source.generated_0.open_events", + "fqn": [ + "generated_0", + "open_events" + ], + "source_name": "open_events", + "source_description": "", + "loader": "", + "identifier": "open_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Events whose columns are only known to the warehouse.", + "columns": {}, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_0", + "fqn": [ + "generated_0", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_1", + "fqn": [ + "generated_0", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_0.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_0.adjust_0_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_0_round": { + "name": "adjust_0_round", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0_round", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_2.py", + "original_file_path": "macros/adjust_2.py", + "unique_id": "macro.generated_0.adjust_2", + "macro_sql": "def adjust_2(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_0.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'east'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_0.adjust_1", + "macro_sql": "import os\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Tag an amount with the deployment region.\"\"\"\n region = os.environ.get(\"SQB_DIFFERENTIAL_REGION\", \"east\")\n return f\"({expression} + LENGTH('{region}'))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/fulfillment/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_0__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_0__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_0.banded_amounts": [ + "model.generated_0.table_fn__amount_bands" + ], + "model.generated_0.chain_1_stg_sales_0": [ + "model.generated_0.contracted_stg_sales_0" + ], + "model.generated_0.chain_2_stg_sales_0": [ + "model.generated_0.chain_1_stg_sales_0" + ], + "model.generated_0.chain_3_stg_sales_0": [ + "model.generated_0.chain_2_stg_sales_0" + ], + "model.generated_0.checked_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.combined_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_1" + ], + "model.generated_0.contracted_stg_sales_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.every_open_event": [ + "source.generated_0.open_events" + ], + "model.generated_0.every_raw_events_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.every_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.passed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.regional_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.scaled_stg_fulfillment_0": [ + "model.generated_0.scaled_amount", + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.typed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.unanalysed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_0": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.fulfillment_summary_1": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_2": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ], + "model.generated_0.stg_fulfillment_0": [ + "source.generated_0.raw_events_1" + ], + "model.generated_0.stg_fulfillment_1": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.sales_summary_0": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.sales_summary_1": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ], + "model.generated_0.sales_summary_2": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.stg_sales_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.stg_sales_1": [ + "source.generated_0.raw_events_1" + ], + "source.generated_0.open_events": [], + "source.generated_0.raw_events_0": [], + "source.generated_0.raw_events_1": [], + "seed.generated_0.lookup_0": [], + "seed.generated_0.lookup_1": [], + "model.generated_0.scaled_amount": [], + "model.generated_0.table_fn__amount_bands": [ + "model.generated_0.stg_fulfillment_0" + ] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/0.json b/tests/goldens/compiler/seed/0.json new file mode 100644 index 0000000000..3446f321b7 --- /dev/null +++ b/tests/goldens/compiler/seed/0.json @@ -0,0 +1,3599 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-select", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-no-analysis", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-rich-lineage", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/configured_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"configured_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN ('1')", + "" + ], + "audits/generic/configured_stg_sales_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"configured_stg_sales_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'shipped')", + "" + ], + "audits/generic/configured_stg_sales_1/configured_amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"configured_stg_sales_1\")", + "WHERE amount < -35", + "" + ], + "audits/generic/configured_stg_sales_1/configured_id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"configured_stg_sales_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_stg_sales_1/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __ref(\"configured_stg_sales_1\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/fulfillment_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"fulfillment_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/labelled_stg_fulfillment_0/tidy_status__status.sql": [ + "SELECT *", + "FROM __ref(\"labelled_stg_fulfillment_0\")", + "WHERE status <> LOWER(TRIM(status))", + "" + ], + "audits/generic/sales_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_2/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_2\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/shaped_stg_sales_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"shaped_stg_sales_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_fulfillment_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id IS NULL", + "" + ], + "audits/singular/fulfillment_summary_2_matches.sql": [ + "SELECT a.id", + "FROM __ref(\"fulfillment_summary_2\") a", + "LEFT JOIN __ref(\"fulfillment_summary_0\") b ON a.id = b.id", + "WHERE b.id IS NULL", + "" + ], + "audits/singular/labelled_channels_match.sql": [ + "SELECT l.id", + "FROM __ref(\"labelled_stg_fulfillment_0\") l", + "JOIN __ref(\"channel_labels\") c ON l.id = c.id", + "WHERE l.status = c.channel", + "" + ], + "functions/python/is_large.sql": [ + "REGISTER PYTHON FUNCTION is_large(DOUBLE) RETURNS BOOLEAN", + "" + ], + "functions/sql/configured_label.sql": [ + "CREATE OR REPLACE MACRO ci_checks.configured_label(raw_status) AS (", + "UPPER(raw_status)", + ")", + "" + ], + "functions/sql/is_placed.sql": [ + "CREATE OR REPLACE MACRO ci_checks.is_placed(event_status) AS (", + "event_status = 'placed'", + ")", + "" + ], + "functions/sql/table_fn__events_above.sql": [ + "CREATE OR REPLACE MACRO ci_checks.table_fn__events_above(p_minimum) AS TABLE", + "SELECT id, amount", + "FROM __ref(\"stg_sales_1\")", + "WHERE amount > p_minimum", + "" + ], + "functions/sql/tidy_status.sql": [ + "CREATE OR REPLACE MACRO ci_checks.tidy_status(raw_status) AS (", + "LOWER(TRIM(raw_status))", + ")", + "" + ], + "models/analysis/cte_facts_stg_fulfillment_1.sql": [ + "WITH base AS (", + " SELECT id, CAST(amount AS DECIMAL(12, 2)) AS amount, 'event' AS kind,", + " COALESCE(status, 'unknown') AS status", + " FROM __ref(\"stg_fulfillment_1\")", + " WHERE id IS NOT NULL", + ")", + "SELECT id + 0 AS id, amount, UPPER(kind) AS kind, UPPER(status) AS status", + "FROM base", + "" + ], + "models/analysis/pivot_input_stg_sales_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR) AS status, amount", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/analysis/pivoted_stg_sales_0.sql": [ + "PIVOT __ref(\"pivot_input_stg_sales_0\")", + "ON status", + "USING MAX(amount)", + "GROUP BY id", + "" + ], + "models/analysis/regional_stg_fulfillment_0.sql": [ + "SELECT id, amount, 'east' AS region", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/unanalysed_stg_sales_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_sales_0\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/features/append_stg_fulfillment_1.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/features/batched_rolling_window_stg_sales_0.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_sales_0\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/flagged_stg_fulfillment_0.sql": [ + "SELECT id, __udf(\"is_placed\")(status) AS is_placed,", + " __udf(\"is_large\")(amount) AS is_large", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/features/product_labels.sql": [ + "SELECT id, label", + "FROM __source(\"loaded_products\")", + "" + ], + "models/features/shaped_stg_sales_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/features/taxed_stg_fulfillment_0.sql": [ + "SELECT id, ROUND(amount * 1.2, 2) AS taxed, ROUND(amount, 1) AS rounded", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/fulfillment/marts/fulfillment_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 0.1)) AS adjust_2_amount,", + " j2.label AS lookup_label_2,", + " 'naïve résumé' AS site_label", + "FROM __ref(\"stg_fulfillment_0\") t", + "LEFT JOIN __ref(\"stg_sales_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/fulfillment/marts/fulfillment_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_fulfillment_0\") t", + "" + ], + "models/fulfillment/marts/fulfillment_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 0.1)) AS adjust_2_amount,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_fulfillment_1\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "" + ], + "models/fulfillment/staging/stg_fulfillment_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'naïve résumé' AS site_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " 'naïve résumé' AS site_label", + "FROM __source(\"raw_events_0\") t", + "WHERE t.status <> 'expédié'", + "" + ], + "models/rendering/bounded_stg_fulfillment_1.sql": [ + "SELECT id, amount, created_at", + "FROM __ref(\"stg_fulfillment_1\")", + "WHERE created_at >= __cursor_start()", + " AND created_at < __cursor_end()", + "" + ], + "models/rendering/channel_labels.sql": [ + "SELECT id, channel", + "FROM __source(\"labelled_channels\")", + "" + ], + "models/rendering/configured_stg_sales_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_sales_1\")", + "" + ], + "models/rendering/labelled_stg_fulfillment_0.sql": [ + "SELECT id, LOWER(TRIM(status)) AS status,", + " __udf(\"tidy_status\")(status) AS tidied", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/rendering/large_events.sql": [ + "SELECT id, amount", + "FROM __table_fn(\"table_fn__events_above\")(4)", + "" + ], + "models/rendering/latest_raw_events_1.sql": [ + "SELECT id, amount", + "FROM (SELECT id, amount FROM __source(\"raw_events_1\") ORDER BY id DESC LIMIT 2) AS latest", + "" + ], + "models/rendering/unioned_event_ids.sql": [ + "SELECT id", + "FROM (SELECT id FROM __ref(\"stg_sales_0\") UNION ALL SELECT id FROM __ref(\"stg_sales_1\")) AS unioned", + "" + ], + "models/sales/marts/sales_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_1\") j1 ON t.id = j1.id", + "" + ], + "models/sales/marts/sales_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 0.1)) AS adjust_2_amount,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "WHERE t.status <> '取消'", + "" + ], + "models/sales/marts/sales_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " j2.label AS lookup_label_2", + "FROM __ref(\"stg_sales_1\") t", + "LEFT JOIN __ref(\"stg_fulfillment_0\") j1 ON t.id = j1.id", + "LEFT JOIN __seed(\"lookup_1\") j2 ON t.id = j2.id", + "" + ], + "models/sales/staging/stg_sales_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * '1e-07' AS threshold_2_amount,", + " 'naïve résumé' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/sales/staging/stg_sales_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label", + "FROM __source(\"raw_events_1\") t", + "" + ], + "tests/_chain_/labelled_stg_fulfillment_0__stg_fulfillment_0/test_labelled_stg_fulfillment_0.sql": [ + "WITH __source__raw_events_1 AS (SELECT 1 AS id, CAST(1 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-01 00:00:00' AS created_at UNION ALL SELECT 2 AS id, CAST(2 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-02 00:00:00' AS created_at),", + "__ref__stg_fulfillment_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'naïve résumé' AS site_label", + "FROM __source__raw_events_1 t),", + "__ref__labelled_stg_fulfillment_0 AS (SELECT id, LOWER(TRIM(status)) AS status,", + " ci_checks.tidy_status(status) AS tidied", + "FROM __ref__stg_fulfillment_0),", + "__actual__labelled_stg_fulfillment_0 AS (SELECT * FROM __ref__labelled_stg_fulfillment_0),", + "__expected__labelled_stg_fulfillment_0 AS (SELECT 1 AS id, LOWER(TRIM('placed')) AS status", + " UNION ALL", + " SELECT 2 AS id, 'placed' AS status)", + "SELECT 1 AS step_index, 'labelled_stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__labelled_stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__labelled_stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__labelled_stg_fulfillment_0 EXCEPT SELECT id, status FROM __expected__labelled_stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__labelled_stg_fulfillment_0 EXCEPT SELECT id, status FROM __actual__labelled_stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/macro taxes_amounts/taxes_amounts.sql": [ + "WITH input_values AS (SELECT 10 AS amount),", + "__actual__macro_taxes_amounts AS (SELECT ROUND(amount * 1.2, 2) AS taxed", + " FROM input_values),", + "__expected__macro_taxes_amounts AS (SELECT 12.0 AS taxed)", + "SELECT 0 AS step_index, 'macro taxes_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_taxes_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_taxes_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_taxes_amounts EXCEPT SELECT * FROM __expected__macro_taxes_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_taxes_amounts EXCEPT SELECT * FROM __actual__macro_taxes_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/regional_stg_fulfillment_0/test_regional_stg_fulfillment_0.sql": [ + "WITH __ref__stg_fulfillment_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_fulfillment_0 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_fulfillment_0),", + "__actual__regional_stg_fulfillment_0 AS (SELECT * FROM __ref__regional_stg_fulfillment_0),", + "__expected__regional_stg_fulfillment_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_fulfillment_0 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_fulfillment_0 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_fulfillment_1/test_stg_fulfillment_1.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_fulfillment_1 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Ελληνικά orders' AS threshold_0_label,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " 'naïve résumé' AS site_label", + "FROM __source__raw_events_0 t", + "WHERE t.status <> 'expédié'),", + "__actual__stg_fulfillment_1 AS (SELECT * FROM __ref__stg_fulfillment_1),", + "__expected__stg_fulfillment_1 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_fulfillment_1' AS model_name, (SELECT COUNT(*) FROM __actual__stg_fulfillment_1) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_fulfillment_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_fulfillment_1 EXCEPT SELECT id, status FROM __expected__stg_fulfillment_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_fulfillment_1 EXCEPT SELECT id, status FROM __actual__stg_fulfillment_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_sales_1_cases/block_1__labelled.sql": [ + "WITH __source__raw_events_1 AS (SELECT 1 AS id, CAST(2.25 AS DOUBLE) AS amount,", + " '東京 warehouse' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_sales_1 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label", + "FROM __source__raw_events_1 t),", + "__actual__stg_sales_1 AS (SELECT * FROM __ref__stg_sales_1),", + "__expected__stg_sales_1 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_sales_1' AS model_name, (SELECT COUNT(*) FROM __actual__stg_sales_1) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_sales_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_sales_1 EXCEPT SELECT id FROM __expected__stg_sales_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_sales_1 EXCEPT SELECT id FROM __actual__stg_sales_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_sales_1_cases/block_1__placed.sql": [ + "WITH __source__raw_events_1 AS (SELECT 1 AS id, CAST(1.5 AS DOUBLE) AS amount,", + " 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_sales_1 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS threshold_1_label", + "FROM __source__raw_events_1 t),", + "__actual__stg_sales_1 AS (SELECT * FROM __ref__stg_sales_1),", + "__expected__stg_sales_1 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_sales_1' AS model_name, (SELECT COUNT(*) FROM __actual__stg_sales_1) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_sales_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_sales_1 EXCEPT SELECT id FROM __expected__stg_sales_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_sales_1 EXCEPT SELECT id FROM __actual__stg_sales_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/udf detects_placed_events/detects_placed_events.sql": [ + "WITH input_values AS (SELECT 'placed' AS event_status),", + "__actual__udf_detects_placed_events AS (SELECT event_status, ci_checks.is_placed(event_status) AS is_placed", + " FROM input_values),", + "__expected__udf_detects_placed_events AS (SELECT 'placed' AS event_status, TRUE AS is_placed)", + "SELECT 0 AS step_index, 'udf detects_placed_events' AS model_name, (SELECT COUNT(*) FROM __actual__udf_detects_placed_events) AS actual_count, (SELECT COUNT(*) FROM __expected__udf_detects_placed_events) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__udf_detects_placed_events EXCEPT SELECT * FROM __expected__udf_detects_placed_events) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__udf_detects_placed_events EXCEPT SELECT * FROM __actual__udf_detects_placed_events) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_0.cte_facts_stg_fulfillment_1": { + "database": null, + "schema": "ci_checks", + "name": "cte_facts_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/cte_facts_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/cte_facts_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.cte_facts_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "analysis", + "cte_facts_stg_fulfillment_1" + ], + "alias": "cte_facts_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted CTE reads of stg_fulfillment_1", + "columns": { + "id": { + "name": "id", + "description": "Recovered id", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Recovered amount", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "kind": { + "name": "kind", + "description": "Recovered kind", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "Recovered status", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.cte_facts_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.pivot_input_stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "pivot_input_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/pivot_input_stg_sales_0.sql", + "original_file_path": "models/analysis/pivot_input_stg_sales_0.sql", + "unique_id": "model.generated_0.pivot_input_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "pivot_input_stg_sales_0" + ], + "alias": "pivot_input_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted pivot input from stg_sales_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivot_input_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0" + ] + } + }, + "model.generated_0.pivoted_stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "pivoted_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/pivoted_stg_sales_0.sql", + "original_file_path": "models/analysis/pivoted_stg_sales_0.sql", + "unique_id": "model.generated_0.pivoted_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "pivoted_stg_sales_0" + ], + "alias": "pivoted_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amounts of stg_sales_0 pivoted by status", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivoted_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.pivot_input_stg_sales_0" + ] + } + }, + "model.generated_0.regional_stg_fulfillment_0": { + "database": null, + "schema": "ci_checks", + "name": "regional_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/regional_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/regional_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.regional_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "regional_stg_fulfillment_0" + ], + "alias": "regional_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.regional_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.unanalysed_stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "unanalysed_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/analysis/unanalysed_stg_sales_0.sql", + "original_file_path": "models/analysis/unanalysed_stg_sales_0.sql", + "unique_id": "model.generated_0.unanalysed_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "analysis", + "unanalysed_stg_sales_0" + ], + "alias": "unanalysed_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_sales_0 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unanalysed_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0" + ] + } + }, + "model.generated_0.append_stg_fulfillment_1": { + "database": null, + "schema": "ci_checks", + "name": "append_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/append_stg_fulfillment_1.sql", + "original_file_path": "models/features/append_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.append_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "features", + "append_stg_fulfillment_1" + ], + "alias": "append_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "append", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental append copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.append_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.batched_rolling_window_stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "batched_rolling_window_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/batched_rolling_window_stg_sales_0.sql", + "original_file_path": "models/features/batched_rolling_window_stg_sales_0.sql", + "unique_id": "model.generated_0.batched_rolling_window_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "features", + "batched_rolling_window_stg_sales_0" + ], + "alias": "batched_rolling_window_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched rolling_window totals of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.batched_rolling_window_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0" + ] + } + }, + "model.generated_0.flagged_stg_fulfillment_0": { + "database": null, + "schema": "ci_checks", + "name": "flagged_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/flagged_stg_fulfillment_0.sql", + "original_file_path": "models/features/flagged_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.flagged_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "features", + "flagged_stg_fulfillment_0" + ], + "alias": "flagged_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Function-flagged copy of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.flagged_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.is_placed", + "model.generated_0.is_large", + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.product_labels": { + "database": null, + "schema": "ci_checks", + "name": "product_labels", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/product_labels.sql", + "original_file_path": "models/features/product_labels.sql", + "unique_id": "model.generated_0.product_labels", + "fqn": [ + "generated_0", + "models", + "features", + "product_labels" + ], + "alias": "product_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Product labels from the loader", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.product_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.loaded_products" + ] + } + }, + "model.generated_0.shaped_stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "shaped_stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/shaped_stg_sales_0.sql", + "original_file_path": "models/features/shaped_stg_sales_0.sql", + "unique_id": "model.generated_0.shaped_stg_sales_0", + "fqn": [ + "generated_0", + "models", + "features", + "shaped_stg_sales_0" + ], + "alias": "shaped_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Schema-shaped copy of stg_sales_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.shaped_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0" + ] + } + }, + "model.generated_0.taxed_stg_fulfillment_0": { + "database": null, + "schema": "ci_checks", + "name": "taxed_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/features/taxed_stg_fulfillment_0.sql", + "original_file_path": "models/features/taxed_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.taxed_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "features", + "taxed_stg_fulfillment_0" + ], + "alias": "taxed_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Taxed copy of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.taxed_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "fulfillment_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "unique_id": "model.generated_0.fulfillment_summary_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_0" + ], + "alias": "fulfillment_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.fulfillment_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.fulfillment_summary_1": { + "database": null, + "schema": "ci_checks", + "name": "fulfillment_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "unique_id": "model.generated_0.fulfillment_summary_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_1" + ], + "alias": "fulfillment_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.fulfillment_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.fulfillment_summary_2": { + "database": null, + "schema": "ci_checks", + "name": "fulfillment_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_2.sql", + "unique_id": "model.generated_0.fulfillment_summary_2", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "marts", + "fulfillment_summary_2" + ], + "alias": "fulfillment_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.fulfillment_summary_2' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.fulfillment_summary_2' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of fulfillment activity 2 (naïve résumé)", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.fulfillment_summary_2' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Zürich – depot" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.fulfillment_summary_2' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.fulfillment_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.stg_fulfillment_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "unique_id": "model.generated_0.stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_0" + ], + "alias": "stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "model.generated_0.stg_fulfillment_1": { + "database": null, + "schema": "ci_checks", + "name": "stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "unique_id": "model.generated_0.stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "fulfillment", + "staging", + "stg_fulfillment_1" + ], + "alias": "stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.bounded_stg_fulfillment_1": { + "database": null, + "schema": "ci_checks", + "name": "bounded_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/bounded_stg_fulfillment_1.sql", + "original_file_path": "models/rendering/bounded_stg_fulfillment_1.sql", + "unique_id": "model.generated_0.bounded_stg_fulfillment_1", + "fqn": [ + "generated_0", + "models", + "rendering", + "bounded_stg_fulfillment_1" + ], + "alias": "bounded_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Cursor-bounded copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.bounded_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_fulfillment_1" + ] + } + }, + "model.generated_0.channel_labels": { + "database": null, + "schema": "ci_checks", + "name": "channel_labels", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/channel_labels.sql", + "original_file_path": "models/rendering/channel_labels.sql", + "unique_id": "model.generated_0.channel_labels", + "fqn": [ + "generated_0", + "models", + "rendering", + "channel_labels" + ], + "alias": "channel_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Normalised channel labels", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.channel_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.labelled_channels" + ] + } + }, + "model.generated_0.configured_stg_sales_1": { + "database": null, + "schema": "ci_checks", + "name": "configured_stg_sales_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/configured_stg_sales_1.sql", + "original_file_path": "models/rendering/configured_stg_sales_1.sql", + "unique_id": "model.generated_0.configured_stg_sales_1", + "fqn": [ + "generated_0", + "models", + "rendering", + "configured_stg_sales_1" + ], + "alias": "configured_stg_sales_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "release" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "release" + ], + "description": "Configured copy of stg_sales_1 (réglé)", + "columns": { + "id": { + "name": "id", + "description": "Row key", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Montant réglé", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.configured_stg_sales_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_1" + ] + } + }, + "model.generated_0.labelled_stg_fulfillment_0": { + "database": null, + "schema": "ci_checks", + "name": "labelled_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/labelled_stg_fulfillment_0.sql", + "original_file_path": "models/rendering/labelled_stg_fulfillment_0.sql", + "unique_id": "model.generated_0.labelled_stg_fulfillment_0", + "fqn": [ + "generated_0", + "models", + "rendering", + "labelled_stg_fulfillment_0" + ], + "alias": "labelled_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Labelled copy of stg_fulfillment_0", + "columns": { + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.labelled_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.tidy_status", + "model.generated_0.stg_fulfillment_0" + ] + } + }, + "model.generated_0.large_events": { + "database": null, + "schema": "ci_checks", + "name": "large_events", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/large_events.sql", + "original_file_path": "models/rendering/large_events.sql", + "unique_id": "model.generated_0.large_events", + "fqn": [ + "generated_0", + "models", + "rendering", + "large_events" + ], + "alias": "large_events", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Events above a threshold from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.large_events", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.table_fn__events_above" + ] + } + }, + "model.generated_0.latest_raw_events_1": { + "database": null, + "schema": "ci_checks", + "name": "latest_raw_events_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/latest_raw_events_1.sql", + "original_file_path": "models/rendering/latest_raw_events_1.sql", + "unique_id": "model.generated_0.latest_raw_events_1", + "fqn": [ + "generated_0", + "models", + "rendering", + "latest_raw_events_1" + ], + "alias": "latest_raw_events_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Newest rows of raw_events_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.latest_raw_events_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "model.generated_0.unioned_event_ids": { + "database": null, + "schema": "ci_checks", + "name": "unioned_event_ids", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/rendering/unioned_event_ids.sql", + "original_file_path": "models/rendering/unioned_event_ids.sql", + "unique_id": "model.generated_0.unioned_event_ids", + "fqn": [ + "generated_0", + "models", + "rendering", + "unioned_event_ids" + ], + "alias": "unioned_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids from two staged relations", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unioned_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "model.generated_0.stg_sales_1" + ] + } + }, + "model.generated_0.sales_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "sales_summary_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_0.sql", + "original_file_path": "models/sales/marts/sales_summary_0.sql", + "unique_id": "model.generated_0.sales_summary_0", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_0" + ], + "alias": "sales_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.sales_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.sales_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.sales_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.sales_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.sales_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.sales_summary_1": { + "database": null, + "schema": "ci_checks", + "name": "sales_summary_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_1.sql", + "original_file_path": "models/sales/marts/sales_summary_1.sql", + "unique_id": "model.generated_0.sales_summary_1", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_1" + ], + "alias": "sales_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.sales_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ] + } + }, + "model.generated_0.sales_summary_2": { + "database": null, + "schema": "ci_checks", + "name": "sales_summary_2", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/marts/sales_summary_2.sql", + "original_file_path": "models/sales/marts/sales_summary_2.sql", + "unique_id": "model.generated_0.sales_summary_2", + "fqn": [ + "generated_0", + "models", + "sales", + "marts", + "sales_summary_2" + ], + "alias": "sales_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 2 (Ελληνικά orders)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.sales_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ] + } + }, + "model.generated_0.stg_sales_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_sales_0", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_0.sql", + "original_file_path": "models/sales/staging/stg_sales_0.sql", + "unique_id": "model.generated_0.stg_sales_0", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_0" + ], + "alias": "stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_0" + ] + } + }, + "model.generated_0.stg_sales_1": { + "database": null, + "schema": "ci_checks", + "name": "stg_sales_1", + "resource_type": "model", + "package_name": "generated_0", + "path": "models/sales/staging/stg_sales_1.sql", + "original_file_path": "models/sales/staging/stg_sales_1.sql", + "unique_id": "model.generated_0.stg_sales_1", + "fqn": [ + "generated_0", + "models", + "sales", + "staging", + "stg_sales_1" + ], + "alias": "stg_sales_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_sales_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_0.raw_events_1" + ] + } + }, + "seed.generated_0.lookup_0": { + "database": null, + "schema": "ci_checks", + "name": "lookup_0", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_0.csv", + "original_file_path": "seeds/lookup_0.csv", + "unique_id": "seed.generated_0.lookup_0", + "fqn": [ + "generated_0", + "seeds", + "lookup_0" + ], + "alias": "lookup_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.lookup_0", + "root_path": null, + "depends_on": { + "macros": [] + } + }, + "seed.generated_0.lookup_1": { + "database": null, + "schema": "ci_checks", + "name": "lookup_1", + "resource_type": "seed", + "package_name": "generated_0", + "path": "seeds/lookup_1.csv", + "original_file_path": "seeds/lookup_1.csv", + "unique_id": "seed.generated_0.lookup_1", + "fqn": [ + "generated_0", + "seeds", + "lookup_1" + ], + "alias": "lookup_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.lookup_1", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.generated_0.configured_events": { + "database": null, + "schema": "", + "name": "configured_events", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/configured.yml", + "original_file_path": "sources/configured.yml", + "unique_id": "source.generated_0.configured_events", + "fqn": [ + "generated_0", + "configured_events" + ], + "source_name": "configured_events", + "source_description": "", + "loader": "", + "identifier": "configured_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Configured feed events", + "columns": { + "id": { + "name": "id", + "description": "Key id", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "owner": "orders team" + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.labelled_channels": { + "database": null, + "schema": "", + "name": "labelled_channels", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/labelled.yml", + "original_file_path": "sources/labelled.yml", + "unique_id": "source.generated_0.labelled_channels", + "fqn": [ + "generated_0", + "labelled_channels" + ], + "source_name": "labelled_channels", + "source_description": "", + "loader": "", + "identifier": "labelled_channels", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Channel labels normalised in the source expression.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "channel": { + "name": "channel", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.loaded_products": { + "database": null, + "schema": "ci_checks", + "name": "loaded_products", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/managed.yml", + "original_file_path": "sources/managed.yml", + "unique_id": "source.generated_0.loaded_products", + "fqn": [ + "generated_0", + "loaded_products" + ], + "source_name": "loaded_products", + "source_description": "", + "loader": "", + "identifier": "loaded_products", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Products loaded by a project loader.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "loaded_products", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_0", + "fqn": [ + "generated_0", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_0.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_0", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_0.raw_events_1", + "fqn": [ + "generated_0", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_0.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_0.adjust_0_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_0_round": { + "name": "adjust_0_round", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_0.adjust_0_round", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/adjust_2.py", + "original_file_path": "macros/adjust_2.py", + "unique_id": "macro.generated_0.adjust_2", + "macro_sql": "def adjust_2(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.tidy_label": { + "name": "tidy_label", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/labels.py", + "original_file_path": "macros/labels.py", + "unique_id": "macro.generated_0.tidy_label", + "macro_sql": "def tidy_label(expression: str) -> str:\n \"\"\"Trim and lower-case a label.\"\"\"\n return f\"LOWER(TRIM({expression}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.round_amount": { + "name": "round_amount", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/rounding.py", + "original_file_path": "macros/rounding.py", + "unique_id": "macro.generated_0.round_amount", + "macro_sql": "def round_amount(expression: str, places: int = 2) -> str:\n \"\"\"Round an amount.\"\"\"\n return f\"ROUND({expression}, {places})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.taxed": { + "name": "taxed", + "resource_type": "macro", + "package_name": "generated_0", + "path": "macros/tax.py", + "original_file_path": "macros/tax.py", + "unique_id": "macro.generated_0.taxed", + "macro_sql": "from macros.rounding import round_amount\n\n\ndef taxed(expression: str) -> str:\n \"\"\"Add tax to an amount, rounded.\"\"\"\n return round_amount(f\"{expression} * 1.2\")\n", + "depends_on": { + "macros": [ + "macro.generated_0.round_amount" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_0.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'east'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/fulfillment/staging/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_0.adjust_1", + "macro_sql": "import os\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Tag an amount with the deployment region.\"\"\"\n region = os.environ.get(\"SQB_DIFFERENTIAL_REGION\", \"east\")\n return f\"({expression} + LENGTH('{region}'))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/fulfillment/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.latest_rows": { + "name": "latest_rows", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_0.latest_rows", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.union_ids": { + "name": "union_ids", + "resource_type": "macro", + "package_name": "generated_0", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_0.union_ids", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0.event_rows": { + "name": "event_rows", + "resource_type": "macro", + "package_name": "generated_0", + "path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "original_file_path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "unique_id": "macro.generated_0.event_rows", + "macro_sql": "def event_rows(count: int = 2) -> str:\n \"\"\"Return fixture event rows.\"\"\"\n return \" UNION ALL \".join(\n f\"SELECT {index} AS id, CAST({index} AS DOUBLE) AS amount, \"\n f\"'placed' AS status, \"\n f\"TIMESTAMP '2026-01-0{index} 00:00:00' AS created_at\"\n for index in range(1, count + 1)\n )\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_0__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_0__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_0__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_0.cte_facts_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.pivot_input_stg_sales_0": [ + "model.generated_0.stg_sales_0" + ], + "model.generated_0.pivoted_stg_sales_0": [ + "model.generated_0.pivot_input_stg_sales_0" + ], + "model.generated_0.regional_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.unanalysed_stg_sales_0": [ + "model.generated_0.stg_sales_0" + ], + "model.generated_0.append_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.batched_rolling_window_stg_sales_0": [ + "model.generated_0.stg_sales_0" + ], + "model.generated_0.flagged_stg_fulfillment_0": [ + "model.generated_0.is_placed", + "model.generated_0.is_large", + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.product_labels": [ + "source.generated_0.loaded_products" + ], + "model.generated_0.shaped_stg_sales_0": [ + "model.generated_0.stg_sales_0" + ], + "model.generated_0.taxed_stg_fulfillment_0": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_0": [ + "model.generated_0.stg_fulfillment_0", + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.fulfillment_summary_1": [ + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.fulfillment_summary_2": [ + "model.generated_0.stg_fulfillment_1", + "seed.generated_0.lookup_0" + ], + "model.generated_0.stg_fulfillment_0": [ + "source.generated_0.raw_events_1" + ], + "model.generated_0.stg_fulfillment_1": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.bounded_stg_fulfillment_1": [ + "model.generated_0.stg_fulfillment_1" + ], + "model.generated_0.channel_labels": [ + "source.generated_0.labelled_channels" + ], + "model.generated_0.configured_stg_sales_1": [ + "model.generated_0.stg_sales_1" + ], + "model.generated_0.labelled_stg_fulfillment_0": [ + "model.generated_0.tidy_status", + "model.generated_0.stg_fulfillment_0" + ], + "model.generated_0.large_events": [ + "model.generated_0.table_fn__events_above" + ], + "model.generated_0.latest_raw_events_1": [ + "source.generated_0.raw_events_1" + ], + "model.generated_0.unioned_event_ids": [ + "model.generated_0.stg_sales_0", + "model.generated_0.stg_sales_1" + ], + "model.generated_0.sales_summary_0": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.sales_summary_1": [ + "model.generated_0.stg_sales_0", + "seed.generated_0.lookup_0" + ], + "model.generated_0.sales_summary_2": [ + "model.generated_0.stg_sales_1", + "model.generated_0.stg_fulfillment_0", + "seed.generated_0.lookup_1" + ], + "model.generated_0.stg_sales_0": [ + "source.generated_0.raw_events_0" + ], + "model.generated_0.stg_sales_1": [ + "source.generated_0.raw_events_1" + ], + "source.generated_0.configured_events": [], + "source.generated_0.labelled_channels": [], + "source.generated_0.loaded_products": [], + "source.generated_0.raw_events_0": [], + "source.generated_0.raw_events_1": [], + "seed.generated_0.lookup_0": [], + "seed.generated_0.lookup_1": [], + "model.generated_0.configured_label": [], + "model.generated_0.is_placed": [], + "model.generated_0.table_fn__events_above": [ + "model.generated_0.stg_sales_1" + ], + "model.generated_0.tidy_status": [], + "model.generated_0.is_large": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/1.json b/tests/goldens/compiler/seed/1.json new file mode 100644 index 0000000000..49b3078359 --- /dev/null +++ b/tests/goldens/compiler/seed/1.json @@ -0,0 +1,37 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/features/dbt_order_counts.sql uses __dbt_ref(\"upstream_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "C214", + "message": "Model file models/features/dbt_order_counts.sql uses __dbt_ref(\"upstream_orders\") but no dbt manifest was found", + "help": "Run dbt compile or configure dbt target_path so SQLBuild can read manifest.json." + } + ] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/seed/10.json b/tests/goldens/compiler/seed/10.json new file mode 100644 index 0000000000..4ca491f751 --- /dev/null +++ b/tests/goldens/compiler/seed/10.json @@ -0,0 +1,3422 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-select", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-no-analysis", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-rich-lineage", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/audited_stg_fulfillment_1/id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"audited_stg_fulfillment_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/checked_stg_fulfillment_0/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_fulfillment_0\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_fulfillment_0/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_fulfillment_0\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_fulfillment_0/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_fulfillment_0\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_fulfillment_0\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/fulfillment_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"fulfillment_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/guarded_stg_inventory_1/amount_at_least__amount.sql": [ + "SELECT *", + "FROM __ref(\"guarded_stg_inventory_1\")", + "WHERE amount < 0", + "" + ], + "audits/generic/stated_stg_fulfillment_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"stated_stg_fulfillment_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/stg_fulfillment_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_inventory_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_inventory_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_sales_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_sales_0\")", + "WHERE id IS NULL", + "" + ], + "audits/singular/fulfillment_summary_1_matches.sql": [ + "SELECT a.id", + "FROM __ref(\"fulfillment_summary_1\") a", + "LEFT JOIN __ref(\"fulfillment_summary_0\") b ON a.id = b.id", + "WHERE b.id IS NULL", + "" + ], + "functions/python/is_large.sql": [ + "REGISTER PYTHON FUNCTION is_large(DOUBLE) RETURNS BOOLEAN", + "" + ], + "functions/sql/is_placed.sql": [ + "CREATE OR REPLACE MACRO main.is_placed(event_status) AS (", + "event_status = 'placed'", + ")", + "" + ], + "functions/sql/table_fn__events_above.sql": [ + "CREATE OR REPLACE MACRO main.table_fn__events_above(p_minimum) AS TABLE", + "SELECT id, amount", + "FROM __ref(\"stg_inventory_0\")", + "WHERE amount > p_minimum", + "" + ], + "models/analysis/chain_1_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"contracted_stg_sales_0\")", + "" + ], + "models/analysis/chain_2_stg_sales_0.sql": [ + "SELECT id, UPPER(label) AS label, amount", + "FROM __ref(\"chain_1_stg_sales_0\")", + "" + ], + "models/analysis/chain_3_stg_sales_0.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"chain_2_stg_sales_0\")", + "" + ], + "models/analysis/checked_stg_fulfillment_0.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/analysis/contracted_stg_sales_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR(34)) AS label,", + " amount", + "FROM __source(\"raw_events_1\")", + "" + ], + "models/analysis/cte_facts_stg_sales_0.sql": [ + "WITH base AS (", + " SELECT id, CAST(amount AS DECIMAL(12, 2)) AS amount, 'event' AS kind,", + " COALESCE(status, 'unknown') AS status", + " FROM __ref(\"stg_sales_0\")", + " WHERE id IS NOT NULL", + ")", + "SELECT id + 0 AS id, amount, UPPER(kind) AS kind, UPPER(status) AS status", + "FROM base", + "" + ], + "models/analysis/regional_stg_inventory_0.sql": [ + "SELECT id, amount, 'north' AS region", + "FROM __ref(\"stg_inventory_0\")", + "" + ], + "models/features/audited_stg_fulfillment_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/features/check_history_stg_fulfillment_1.sql": [ + "SELECT id, status, amount", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/features/copied_stg_sales_0.sql": [ + "SELECT id, status", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/features/flagged_stg_inventory_1.sql": [ + "SELECT id, __udf(\"is_placed\")(status) AS is_placed,", + " __udf(\"is_large\")(amount) AS is_large", + "FROM __ref(\"stg_inventory_1\")", + "" + ], + "models/features/guarded_stg_inventory_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_inventory_1\")", + "" + ], + "models/features/merge_stg_sales_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/features/product_labels.sql": [ + "SELECT id, label", + "FROM __source(\"loaded_products\")", + "" + ], + "models/features/spaced_stg_sales_0.sql": [ + "-- Généré pour 東京 warehouse", + "SELECT", + "\tid,", + "\t'naïve résumé' AS label, -- étiquette ✓", + "\tamount", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/features/taxed_stg_sales_0.sql": [ + "SELECT id, ROUND(amount * 1.2, 2) AS taxed, ROUND(amount, 1) AS rounded", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/fulfillment/marts/fulfillment_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 12345.678)) AS adjust_0_amount", + "FROM __ref(\"stg_fulfillment_1\") t", + "" + ], + "models/fulfillment/marts/fulfillment_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_fulfillment_0\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 12345.678)) AS adjust_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount", + "FROM __source(\"raw_events_2\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 3 AS priority,", + " (t.amount * (1 - 12345.678)) AS adjust_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/inventory/marts/inventory_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 3 AS priority,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount", + "FROM __ref(\"stg_inventory_1\") t", + "" + ], + "models/inventory/marts/inventory_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_inventory_1\") t", + "" + ], + "models/inventory/staging/stg_inventory_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/inventory/staging/stg_inventory_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'naïve résumé' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/rendering/large_events.sql": [ + "SELECT id, amount", + "FROM __table_fn(\"table_fn__events_above\")(1.5)", + "" + ], + "models/rendering/latest_raw_events_2.sql": [ + "SELECT id, amount", + "FROM (SELECT id, amount FROM __source(\"raw_events_2\") ORDER BY id DESC LIMIT 2) AS latest", + "" + ], + "models/rendering/stated_stg_fulfillment_1.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status,", + " CASE WHEN amount >= 3 THEN 'HIGH'", + " ELSE 'LOW' END AS tier", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/rendering/unioned_event_ids.sql": [ + "SELECT id", + "FROM (SELECT id FROM __ref(\"stg_fulfillment_0\") UNION ALL SELECT id FROM __ref(\"stg_fulfillment_1\")) AS unioned", + "" + ], + "models/sales/marts/sales_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 3 AS priority,", + " 'naïve résumé' AS site_label", + "FROM __ref(\"stg_sales_0\") t", + "WHERE t.status <> 'returned ✓'", + "" + ], + "models/sales/staging/stg_sales_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 117 AS threshold_0_amount", + "FROM __source(\"raw_events_1\") t", + "" + ], + "tests/macro taxes_amounts/taxes_amounts.sql": [ + "WITH input_values AS (SELECT 10 AS amount),", + "__actual__macro_taxes_amounts AS (SELECT ROUND(amount * 1.2, 2) AS taxed", + " FROM input_values),", + "__expected__macro_taxes_amounts AS (SELECT 12.0 AS taxed)", + "SELECT 0 AS step_index, 'macro taxes_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_taxes_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_taxes_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_taxes_amounts EXCEPT SELECT * FROM __expected__macro_taxes_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_taxes_amounts EXCEPT SELECT * FROM __actual__macro_taxes_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/regional_stg_inventory_0/test_regional_stg_inventory_0.sql": [ + "WITH __ref__stg_inventory_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_inventory_0 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_inventory_0),", + "__actual__regional_stg_inventory_0 AS (SELECT * FROM __ref__regional_stg_inventory_0),", + "__expected__regional_stg_inventory_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_inventory_0' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_inventory_0) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_inventory_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_inventory_0 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_inventory_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_inventory_0 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_inventory_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_fulfillment_0/test_stg_fulfillment_0.sql": [ + "WITH __source__raw_events_2 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_fulfillment_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount * (1 - 12345.678)) AS adjust_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount", + "FROM __source__raw_events_2 t),", + "__actual__stg_fulfillment_0 AS (SELECT * FROM __ref__stg_fulfillment_0),", + "__expected__stg_fulfillment_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_fulfillment_0 EXCEPT SELECT id, status FROM __expected__stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_fulfillment_0 EXCEPT SELECT id, status FROM __actual__stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/udf detects_placed_events/detects_placed_events.sql": [ + "WITH input_values AS (SELECT 'placed' AS event_status),", + "__actual__udf_detects_placed_events AS (SELECT event_status, main.is_placed(event_status) AS is_placed", + " FROM input_values),", + "__expected__udf_detects_placed_events AS (SELECT 'placed' AS event_status, TRUE AS is_placed)", + "SELECT 0 AS step_index, 'udf detects_placed_events' AS model_name, (SELECT COUNT(*) FROM __actual__udf_detects_placed_events) AS actual_count, (SELECT COUNT(*) FROM __expected__udf_detects_placed_events) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__udf_detects_placed_events EXCEPT SELECT * FROM __expected__udf_detects_placed_events) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__udf_detects_placed_events EXCEPT SELECT * FROM __actual__udf_detects_placed_events) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_10.chain_1_stg_sales_0": { + "database": null, + "schema": "main", + "name": "chain_1_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/chain_1_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_1_stg_sales_0.sql", + "unique_id": "model.generated_10.chain_1_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "chain_1_stg_sales_0" + ], + "alias": "chain_1_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 1 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_1_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.contracted_stg_sales_0" + ] + } + }, + "model.generated_10.chain_2_stg_sales_0": { + "database": null, + "schema": "main", + "name": "chain_2_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/chain_2_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_2_stg_sales_0.sql", + "unique_id": "model.generated_10.chain_2_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "chain_2_stg_sales_0" + ], + "alias": "chain_2_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 2 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_2_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.chain_1_stg_sales_0" + ] + } + }, + "model.generated_10.chain_3_stg_sales_0": { + "database": null, + "schema": "main", + "name": "chain_3_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/chain_3_stg_sales_0.sql", + "original_file_path": "models/analysis/chain_3_stg_sales_0.sql", + "unique_id": "model.generated_10.chain_3_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "chain_3_stg_sales_0" + ], + "alias": "chain_3_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 3 below the contracted copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_3_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.chain_2_stg_sales_0" + ] + } + }, + "model.generated_10.checked_stg_fulfillment_0": { + "database": null, + "schema": "main", + "name": "checked_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/checked_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/checked_stg_fulfillment_0.sql", + "unique_id": "model.generated_10.checked_stg_fulfillment_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "checked_stg_fulfillment_0" + ], + "alias": "checked_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_fulfillment_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.checked_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_0" + ] + } + }, + "model.generated_10.contracted_stg_sales_0": { + "database": null, + "schema": "main", + "name": "contracted_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/contracted_stg_sales_0.sql", + "original_file_path": "models/analysis/contracted_stg_sales_0.sql", + "unique_id": "model.generated_10.contracted_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "contracted_stg_sales_0" + ], + "alias": "contracted_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted copy of raw_events_1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR(34)", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.contracted_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_1" + ] + } + }, + "model.generated_10.cte_facts_stg_sales_0": { + "database": null, + "schema": "main", + "name": "cte_facts_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/cte_facts_stg_sales_0.sql", + "original_file_path": "models/analysis/cte_facts_stg_sales_0.sql", + "unique_id": "model.generated_10.cte_facts_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "cte_facts_stg_sales_0" + ], + "alias": "cte_facts_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted CTE reads of stg_sales_0", + "columns": { + "id": { + "name": "id", + "description": "Recovered id", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Recovered amount", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "kind": { + "name": "kind", + "description": "Recovered kind", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "Recovered status", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.cte_facts_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.regional_stg_inventory_0": { + "database": null, + "schema": "main", + "name": "regional_stg_inventory_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/analysis/regional_stg_inventory_0.sql", + "original_file_path": "models/analysis/regional_stg_inventory_0.sql", + "unique_id": "model.generated_10.regional_stg_inventory_0", + "fqn": [ + "generated_10", + "models", + "analysis", + "regional_stg_inventory_0" + ], + "alias": "regional_stg_inventory_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_inventory_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.regional_stg_inventory_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_inventory_0" + ] + } + }, + "model.generated_10.audited_stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "audited_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/audited_stg_fulfillment_1.sql", + "original_file_path": "models/features/audited_stg_fulfillment_1.sql", + "unique_id": "model.generated_10.audited_stg_fulfillment_1", + "fqn": [ + "generated_10", + "models", + "features", + "audited_stg_fulfillment_1" + ], + "alias": "audited_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Factory-audited copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.audited_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_1" + ] + } + }, + "model.generated_10.check_history_stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "check_history_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/check_history_stg_fulfillment_1.sql", + "original_file_path": "models/features/check_history_stg_fulfillment_1.sql", + "unique_id": "model.generated_10.check_history_stg_fulfillment_1", + "fqn": [ + "generated_10", + "models", + "features", + "check_history_stg_fulfillment_1" + ], + "alias": "check_history_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "snapshot", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Check history of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.check_history_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_1" + ] + } + }, + "model.generated_10.copied_stg_sales_0": { + "database": null, + "schema": "main", + "name": "copied_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/copied_stg_sales_0.sql", + "original_file_path": "models/features/copied_stg_sales_0.sql", + "unique_id": "model.generated_10.copied_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "features", + "copied_stg_sales_0" + ], + "alias": "copied_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "copy_table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Custom copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.copied_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.flagged_stg_inventory_1": { + "database": null, + "schema": "main", + "name": "flagged_stg_inventory_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/flagged_stg_inventory_1.sql", + "original_file_path": "models/features/flagged_stg_inventory_1.sql", + "unique_id": "model.generated_10.flagged_stg_inventory_1", + "fqn": [ + "generated_10", + "models", + "features", + "flagged_stg_inventory_1" + ], + "alias": "flagged_stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Function-flagged copy of stg_inventory_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.flagged_stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.is_placed", + "model.generated_10.is_large", + "model.generated_10.stg_inventory_1" + ] + } + }, + "model.generated_10.guarded_stg_inventory_1": { + "database": null, + "schema": "main", + "name": "guarded_stg_inventory_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/guarded_stg_inventory_1.sql", + "original_file_path": "models/features/guarded_stg_inventory_1.sql", + "unique_id": "model.generated_10.guarded_stg_inventory_1", + "fqn": [ + "generated_10", + "models", + "features", + "guarded_stg_inventory_1" + ], + "alias": "guarded_stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Generic-audited copy of stg_inventory_1", + "columns": { + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.guarded_stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_inventory_1" + ] + } + }, + "model.generated_10.merge_stg_sales_0": { + "database": null, + "schema": "main", + "name": "merge_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/merge_stg_sales_0.sql", + "original_file_path": "models/features/merge_stg_sales_0.sql", + "unique_id": "model.generated_10.merge_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "features", + "merge_stg_sales_0" + ], + "alias": "merge_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "merge", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental merge copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.merge_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.product_labels": { + "database": null, + "schema": "main", + "name": "product_labels", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/product_labels.sql", + "original_file_path": "models/features/product_labels.sql", + "unique_id": "model.generated_10.product_labels", + "fqn": [ + "generated_10", + "models", + "features", + "product_labels" + ], + "alias": "product_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Product labels from the loader", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.product_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.loaded_products" + ] + } + }, + "model.generated_10.spaced_stg_sales_0": { + "database": null, + "schema": "main", + "name": "spaced_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/spaced_stg_sales_0.sql", + "original_file_path": "models/features/spaced_stg_sales_0.sql", + "unique_id": "model.generated_10.spaced_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "features", + "spaced_stg_sales_0" + ], + "alias": "spaced_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "línea", + "東京" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "línea", + "東京" + ], + "description": "Copy of stg_sales_0 with café ☕ counter", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.spaced_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.taxed_stg_sales_0": { + "database": null, + "schema": "main", + "name": "taxed_stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/features/taxed_stg_sales_0.sql", + "original_file_path": "models/features/taxed_stg_sales_0.sql", + "unique_id": "model.generated_10.taxed_stg_sales_0", + "fqn": [ + "generated_10", + "models", + "features", + "taxed_stg_sales_0" + ], + "alias": "taxed_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Taxed copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.taxed_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.fulfillment_summary_0": { + "database": null, + "schema": "main", + "name": "fulfillment_summary_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "unique_id": "model.generated_10.fulfillment_summary_0", + "fqn": [ + "generated_10", + "models", + "fulfillment", + "marts", + "fulfillment_summary_0" + ], + "alias": "fulfillment_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "fulfillment", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "fulfillment", + "marts" + ], + "description": "Summary of fulfillment activity 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.fulfillment_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_1" + ] + } + }, + "model.generated_10.fulfillment_summary_1": { + "database": null, + "schema": "main", + "name": "fulfillment_summary_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_1.sql", + "unique_id": "model.generated_10.fulfillment_summary_1", + "fqn": [ + "generated_10", + "models", + "fulfillment", + "marts", + "fulfillment_summary_1" + ], + "alias": "fulfillment_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "fulfillment", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "fulfillment", + "marts" + ], + "description": "Summary of fulfillment activity 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.fulfillment_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_0" + ] + } + }, + "model.generated_10.stg_fulfillment_0": { + "database": null, + "schema": "main", + "name": "stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "unique_id": "model.generated_10.stg_fulfillment_0", + "fqn": [ + "generated_10", + "models", + "fulfillment", + "staging", + "stg_fulfillment_0" + ], + "alias": "stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_2" + ] + } + }, + "model.generated_10.stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "unique_id": "model.generated_10.stg_fulfillment_1", + "fqn": [ + "generated_10", + "models", + "fulfillment", + "staging", + "stg_fulfillment_1" + ], + "alias": "stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_0" + ] + } + }, + "model.generated_10.inventory_summary_0": { + "database": null, + "schema": "main", + "name": "inventory_summary_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/inventory/marts/inventory_summary_0.sql", + "original_file_path": "models/inventory/marts/inventory_summary_0.sql", + "unique_id": "model.generated_10.inventory_summary_0", + "fqn": [ + "generated_10", + "models", + "inventory", + "marts", + "inventory_summary_0" + ], + "alias": "inventory_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "inventory", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.inventory_summary_0' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.inventory_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "inventory", + "marts" + ], + "description": "Summary of inventory activity 0 (東京 warehouse)", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_0' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "café ☕ counter" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.inventory_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_inventory_1" + ] + } + }, + "model.generated_10.inventory_summary_1": { + "database": null, + "schema": "main", + "name": "inventory_summary_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/inventory/marts/inventory_summary_1.sql", + "original_file_path": "models/inventory/marts/inventory_summary_1.sql", + "unique_id": "model.generated_10.inventory_summary_1", + "fqn": [ + "generated_10", + "models", + "inventory", + "marts", + "inventory_summary_1" + ], + "alias": "inventory_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "inventory", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.inventory_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.inventory_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "inventory", + "marts" + ], + "description": "Summary of inventory activity 1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_1' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.inventory_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_inventory_1" + ] + } + }, + "model.generated_10.stg_inventory_0": { + "database": null, + "schema": "main", + "name": "stg_inventory_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/inventory/staging/stg_inventory_0.sql", + "original_file_path": "models/inventory/staging/stg_inventory_0.sql", + "unique_id": "model.generated_10.stg_inventory_0", + "fqn": [ + "generated_10", + "models", + "inventory", + "staging", + "stg_inventory_0" + ], + "alias": "stg_inventory_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged inventory events 0 (café ☕ counter)", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_inventory_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_0" + ] + } + }, + "model.generated_10.stg_inventory_1": { + "database": null, + "schema": "main", + "name": "stg_inventory_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/inventory/staging/stg_inventory_1.sql", + "original_file_path": "models/inventory/staging/stg_inventory_1.sql", + "unique_id": "model.generated_10.stg_inventory_1", + "fqn": [ + "generated_10", + "models", + "inventory", + "staging", + "stg_inventory_1" + ], + "alias": "stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged inventory events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_0" + ] + } + }, + "model.generated_10.large_events": { + "database": null, + "schema": "main", + "name": "large_events", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/rendering/large_events.sql", + "original_file_path": "models/rendering/large_events.sql", + "unique_id": "model.generated_10.large_events", + "fqn": [ + "generated_10", + "models", + "rendering", + "large_events" + ], + "alias": "large_events", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Events above a threshold from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.large_events", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.table_fn__events_above" + ] + } + }, + "model.generated_10.latest_raw_events_2": { + "database": null, + "schema": "main", + "name": "latest_raw_events_2", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/rendering/latest_raw_events_2.sql", + "original_file_path": "models/rendering/latest_raw_events_2.sql", + "unique_id": "model.generated_10.latest_raw_events_2", + "fqn": [ + "generated_10", + "models", + "rendering", + "latest_raw_events_2" + ], + "alias": "latest_raw_events_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Newest rows of raw_events_2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.latest_raw_events_2", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_2" + ] + } + }, + "model.generated_10.stated_stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "stated_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/rendering/stated_stg_fulfillment_1.sql", + "original_file_path": "models/rendering/stated_stg_fulfillment_1.sql", + "unique_id": "model.generated_10.stated_stg_fulfillment_1", + "fqn": [ + "generated_10", + "models", + "rendering", + "stated_stg_fulfillment_1" + ], + "alias": "stated_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Enum-typed copy of stg_fulfillment_1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "tier": { + "name": "tier", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stated_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_1" + ] + } + }, + "model.generated_10.unioned_event_ids": { + "database": null, + "schema": "main", + "name": "unioned_event_ids", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/rendering/unioned_event_ids.sql", + "original_file_path": "models/rendering/unioned_event_ids.sql", + "unique_id": "model.generated_10.unioned_event_ids", + "fqn": [ + "generated_10", + "models", + "rendering", + "unioned_event_ids" + ], + "alias": "unioned_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids from two staged relations", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.unioned_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_fulfillment_0", + "model.generated_10.stg_fulfillment_1" + ] + } + }, + "model.generated_10.sales_summary_0": { + "database": null, + "schema": "main", + "name": "sales_summary_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/sales/marts/sales_summary_0.sql", + "original_file_path": "models/sales/marts/sales_summary_0.sql", + "unique_id": "model.generated_10.sales_summary_0", + "fqn": [ + "generated_10", + "models", + "sales", + "marts", + "sales_summary_0" + ], + "alias": "sales_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "sales", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.sales_summary_0' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.sales_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "sales", + "marts" + ], + "description": "Summary of sales activity 0", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.sales_summary_0' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Zürich – depot" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.sales_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.sales_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_10.stg_sales_0" + ] + } + }, + "model.generated_10.stg_sales_0": { + "database": null, + "schema": "main", + "name": "stg_sales_0", + "resource_type": "model", + "package_name": "generated_10", + "path": "models/sales/staging/stg_sales_0.sql", + "original_file_path": "models/sales/staging/stg_sales_0.sql", + "unique_id": "model.generated_10.stg_sales_0", + "fqn": [ + "generated_10", + "models", + "sales", + "staging", + "stg_sales_0" + ], + "alias": "stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_10.raw_events_1" + ] + } + } + }, + "sources": { + "source.generated_10.loaded_products": { + "database": null, + "schema": "main", + "name": "loaded_products", + "resource_type": "source", + "package_name": "generated_10", + "path": "sources/managed.yml", + "original_file_path": "sources/managed.yml", + "unique_id": "source.generated_10.loaded_products", + "fqn": [ + "generated_10", + "loaded_products" + ], + "source_name": "loaded_products", + "source_description": "", + "loader": "", + "identifier": "loaded_products", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Products loaded by a project loader.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "loaded_products", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_10.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_10", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_10.raw_events_0", + "fqn": [ + "generated_10", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_10.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_10", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_10.raw_events_1", + "fqn": [ + "generated_10", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_10.raw_events_2": { + "database": null, + "schema": "", + "name": "raw_events_2", + "resource_type": "source", + "package_name": "generated_10", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_10.raw_events_2", + "fqn": [ + "generated_10", + "raw_events_2" + ], + "source_name": "raw_events_2", + "source_description": "", + "loader": "", + "identifier": "raw_events_2", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 2.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_10.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_10", + "path": "macros/adjust_1.py", + "original_file_path": "macros/adjust_1.py", + "unique_id": "macro.generated_10.adjust_1", + "macro_sql": "def adjust_1_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_1_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_10.adjust_1_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.adjust_1_round": { + "name": "adjust_1_round", + "resource_type": "macro", + "package_name": "generated_10", + "path": "macros/adjust_1.py", + "original_file_path": "macros/adjust_1.py", + "unique_id": "macro.generated_10.adjust_1_round", + "macro_sql": "def adjust_1_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_1_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.round_amount": { + "name": "round_amount", + "resource_type": "macro", + "package_name": "generated_10", + "path": "macros/rounding.py", + "original_file_path": "macros/rounding.py", + "unique_id": "macro.generated_10.round_amount", + "macro_sql": "def round_amount(expression: str, places: int = 2) -> str:\n \"\"\"Round an amount.\"\"\"\n return f\"ROUND({expression}, {places})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.taxed": { + "name": "taxed", + "resource_type": "macro", + "package_name": "generated_10", + "path": "macros/tax.py", + "original_file_path": "macros/tax.py", + "unique_id": "macro.generated_10.taxed", + "macro_sql": "from macros.rounding import round_amount\n\n\ndef taxed(expression: str) -> str:\n \"\"\"Add tax to an amount, rounded.\"\"\"\n return round_amount(f\"{expression} * 1.2\")\n", + "depends_on": { + "macros": [ + "macro.generated_10.round_amount" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_10", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_10.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'north'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_10", + "path": "models/fulfillment/_sqlbuild/macros/adjust_0.py", + "original_file_path": "models/fulfillment/_sqlbuild/macros/adjust_0.py", + "unique_id": "macro.generated_10.adjust_0", + "macro_sql": "def adjust_0(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/fulfillment" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_10", + "path": "models/inventory/staging/_sqlbuild/_macros/adjust_2.py", + "original_file_path": "models/inventory/staging/_sqlbuild/_macros/adjust_2.py", + "unique_id": "macro.generated_10.adjust_2", + "macro_sql": "def adjust_2(expression: str) -> str:\n \"\"\"Offset an amount.\"\"\"\n return f\"({expression} + 2 + 1)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/inventory/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.latest_rows": { + "name": "latest_rows", + "resource_type": "macro", + "package_name": "generated_10", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_10.latest_rows", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10.union_ids": { + "name": "union_ids", + "resource_type": "macro", + "package_name": "generated_10", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_10.union_ids", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_10__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_10__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_10__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_10.chain_1_stg_sales_0": [ + "model.generated_10.contracted_stg_sales_0" + ], + "model.generated_10.chain_2_stg_sales_0": [ + "model.generated_10.chain_1_stg_sales_0" + ], + "model.generated_10.chain_3_stg_sales_0": [ + "model.generated_10.chain_2_stg_sales_0" + ], + "model.generated_10.checked_stg_fulfillment_0": [ + "model.generated_10.stg_fulfillment_0" + ], + "model.generated_10.contracted_stg_sales_0": [ + "source.generated_10.raw_events_1" + ], + "model.generated_10.cte_facts_stg_sales_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.regional_stg_inventory_0": [ + "model.generated_10.stg_inventory_0" + ], + "model.generated_10.audited_stg_fulfillment_1": [ + "model.generated_10.stg_fulfillment_1" + ], + "model.generated_10.check_history_stg_fulfillment_1": [ + "model.generated_10.stg_fulfillment_1" + ], + "model.generated_10.copied_stg_sales_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.flagged_stg_inventory_1": [ + "model.generated_10.is_placed", + "model.generated_10.is_large", + "model.generated_10.stg_inventory_1" + ], + "model.generated_10.guarded_stg_inventory_1": [ + "model.generated_10.stg_inventory_1" + ], + "model.generated_10.merge_stg_sales_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.product_labels": [ + "source.generated_10.loaded_products" + ], + "model.generated_10.spaced_stg_sales_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.taxed_stg_sales_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.fulfillment_summary_0": [ + "model.generated_10.stg_fulfillment_1" + ], + "model.generated_10.fulfillment_summary_1": [ + "model.generated_10.stg_fulfillment_0" + ], + "model.generated_10.stg_fulfillment_0": [ + "source.generated_10.raw_events_2" + ], + "model.generated_10.stg_fulfillment_1": [ + "source.generated_10.raw_events_0" + ], + "model.generated_10.inventory_summary_0": [ + "model.generated_10.stg_inventory_1" + ], + "model.generated_10.inventory_summary_1": [ + "model.generated_10.stg_inventory_1" + ], + "model.generated_10.stg_inventory_0": [ + "source.generated_10.raw_events_0" + ], + "model.generated_10.stg_inventory_1": [ + "source.generated_10.raw_events_0" + ], + "model.generated_10.large_events": [ + "model.generated_10.table_fn__events_above" + ], + "model.generated_10.latest_raw_events_2": [ + "source.generated_10.raw_events_2" + ], + "model.generated_10.stated_stg_fulfillment_1": [ + "model.generated_10.stg_fulfillment_1" + ], + "model.generated_10.unioned_event_ids": [ + "model.generated_10.stg_fulfillment_0", + "model.generated_10.stg_fulfillment_1" + ], + "model.generated_10.sales_summary_0": [ + "model.generated_10.stg_sales_0" + ], + "model.generated_10.stg_sales_0": [ + "source.generated_10.raw_events_1" + ], + "source.generated_10.loaded_products": [], + "source.generated_10.raw_events_0": [], + "source.generated_10.raw_events_1": [], + "source.generated_10.raw_events_2": [], + "model.generated_10.is_placed": [], + "model.generated_10.table_fn__events_above": [ + "model.generated_10.stg_inventory_0" + ], + "model.generated_10.is_large": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/11.json b/tests/goldens/compiler/seed/11.json new file mode 100644 index 0000000000..fb6be39da4 --- /dev/null +++ b/tests/goldens/compiler/seed/11.json @@ -0,0 +1,45 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "MODEL(...) in '/models/fulfillment/marts/fulfillment_summary_0.sql' contains invalid SQLBuild header syntax: expected key at position 267" + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "D002", + "message": "MODEL(...) in '/models/fulfillment/marts/fulfillment_summary_0.sql' contains invalid SQLBuild header syntax: expected key at position 267" + } + ] + }, + { + "label": "plan", + "exit_code": 1, + "diagnostics": [ + "Project discovery START", + "Project assembly START", + "Declaration parsing START", + "Declaration parsing FAIL ()", + "Project assembly FAIL ()", + "Project discovery FAIL ()", + "error[D002]: MODEL(...) in '/models/fulfillment/marts/fulfillment_summary_0.sql' contains invalid SQLBuild header syntax: expected key at position 267", + "", + "" + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/seed/2.json b/tests/goldens/compiler/seed/2.json new file mode 100644 index 0000000000..67c315c293 --- /dev/null +++ b/tests/goldens/compiler/seed/2.json @@ -0,0 +1,84 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'" + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'" + } + ] + }, + { + "label": "plan", + "exit_code": 1, + "diagnostics": [ + "Project discovery START", + "Project assembly START", + "Declaration parsing START", + "Declaration parsing OK ()", + "Python discovery START", + "Python discovery OK ()", + "Project assembly OK ()", + "Project discovery OK ()", + "Compiling project...", + "error[P001]: Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'", + "", + "" + ] + }, + { + "label": "compile-select", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'" + } + ] + }, + { + "label": "compile-no-analysis", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'" + } + ] + }, + { + "label": "compile-rich-lineage", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Model file models/sales/marts/sales_summary_1.sql references unknown model 'missing_model'" + } + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/seed/3.json b/tests/goldens/compiler/seed/3.json new file mode 100644 index 0000000000..ca042e5bf8 --- /dev/null +++ b/tests/goldens/compiler/seed/3.json @@ -0,0 +1,2396 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/audited_event_totals/amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"audited_event_totals\")", + "WHERE amount < -23", + "" + ], + "audits/generic/audited_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"audited_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (1, 2)", + "" + ], + "audits/generic/audited_events/not_null__id.sql": [ + "SELECT id", + "FROM __source(\"audited_events\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/audited_events/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __source(\"audited_events\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/billing_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"billing_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/channel_codes/not_null__id.sql": [ + "SELECT id", + "FROM __seed(\"channel_codes\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/checked_stg_billing_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_billing_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_billing_1/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_billing_1\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_billing_1/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_billing_1\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_billing_1\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/configured_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"configured_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN ('1')", + "" + ], + "audits/generic/configured_stg_billing_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"configured_stg_billing_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'shipped')", + "" + ], + "audits/generic/configured_stg_billing_1/configured_amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"configured_stg_billing_1\")", + "WHERE amount < -25", + "" + ], + "audits/generic/configured_stg_billing_1/configured_id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"configured_stg_billing_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_stg_billing_1/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __ref(\"configured_stg_billing_1\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/stg_billing_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_billing_0\")", + "WHERE id IS NULL", + "" + ], + "functions/sql/configured_label.sql": [ + "CREATE OR REPLACE MACRO main.configured_label(raw_status) AS (", + "UPPER(raw_status)", + ")", + "" + ], + "functions/sql/scaled_amount.sql": [ + "CREATE OR REPLACE MACRO main.scaled_amount(p_amount, p_factor) AS (", + "p_amount * p_factor", + ")", + "" + ], + "functions/sql/table_fn__amount_bands.sql": [ + "CREATE OR REPLACE MACRO main.table_fn__amount_bands(p_floor) AS TABLE", + "SELECT CAST(id AS INTEGER) AS id,", + " CASE WHEN amount > p_floor THEN 'high' ELSE 'low' END AS band", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/analysis/banded_amounts.sql": [ + "SELECT bands.id, bands.band", + "FROM __table_fn(\"table_fn__amount_bands\")(8.5) AS bands", + "" + ], + "models/analysis/checked_stg_billing_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/analysis/regional_stg_billing_1.sql": [ + "SELECT id, amount, 'east' AS region", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/analysis/scaled_stg_billing_1.sql": [ + "SELECT id, __udf(\"scaled_amount\")(amount, 8) AS scaled_amount", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/billing/marts/billing_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 299 AS threshold_2_amount,", + " (t.amount + 0 + 1) AS adjust_0_amount", + "FROM __ref(\"stg_billing_1\") t", + "LEFT JOIN __ref(\"stg_billing_0\") j1 ON t.id = j1.id", + "" + ], + "models/billing/marts/billing_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 299 AS threshold_2_amount", + "FROM __ref(\"stg_billing_1\") t", + "" + ], + "models/billing/staging/stg_billing_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 374 AS threshold_0_amount,", + " 'Zürich – depot' AS threshold_1_label", + "FROM __source(\"raw_events_2\") t", + "" + ], + "models/billing/staging/stg_billing_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Zürich – depot' AS threshold_1_label,", + " t.amount + 299 AS threshold_2_amount,", + " (t.amount * (1 - 0.15)) AS adjust_1_amount", + "FROM __source(\"raw_events_2\") t", + "WHERE t.status <> 'expédié'", + "" + ], + "models/features/batched_watermark_stg_billing_1.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_billing_1\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/hooked_stg_billing_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/features/kept_stg_billing_1.sql": [ + "SELECT id, status, amount * 0.5 AS weighted", + "FROM __ref(\"stg_billing_1\")", + "WHERE status IN ('取消', 'expédié')", + " AND amount * 1.0 IN (0.5, 1.25, 2500.75) OR id > 0", + "" + ], + "models/rendering/audited_event_totals.sql": [ + "SELECT c.label, SUM(e.amount) AS amount", + "FROM __source(\"audited_events\") e", + "JOIN __seed(\"channel_codes\") c ON e.id = c.id", + "GROUP BY c.label", + "" + ], + "models/rendering/configured_stg_billing_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_billing_1\")", + "" + ], + "models/rendering/interpolated_stg_billing_0.sql": [ + "SELECT id,", + " '東京 warehouse' AS site,", + " $$--東京 warehouse /* $$ AS site_note,", + " 'web-orders' AS channel,", + " amount * 0.15 AS discounted", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/rendering/legacy_event_ids.sql": [ + "SELECT id", + "FROM __ref(\"stg_billing_1\") AS legacy", + "" + ], + "models/rendering/policy_stg_billing_1.sql": [ + "SELECT id, amount, ('web' || '/dev/generated_duckdb/south' || '@web-orders') AS channel,", + " 4 AS minimum_amount,", + " 'store' AS fallback_channel", + "FROM __ref(\"stg_billing_1\")", + "WHERE amount >= 4", + "" + ], + "models/rendering/windowed_stg_billing_0.sql": [ + "SELECT id, created_at", + "FROM __ref(\"stg_billing_0\")", + "WHERE CAST(created_at AS DATE) >= CAST(@@@window_start AS DATE)", + "" + ], + "tests/macro doubles_amounts/doubles_amounts.sql": [ + "WITH input_values AS (SELECT 4 AS amount),", + "__actual__macro_doubles_amounts AS (SELECT (amount * 2) AS doubled", + " FROM input_values),", + "__expected__macro_doubles_amounts AS (SELECT 8 AS doubled)", + "SELECT 0 AS step_index, 'macro doubles_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_doubles_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_doubles_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_doubles_amounts EXCEPT SELECT * FROM __expected__macro_doubles_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_doubles_amounts EXCEPT SELECT * FROM __actual__macro_doubles_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/regional_stg_billing_1/test_regional_stg_billing_1.sql": [ + "WITH __ref__stg_billing_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_billing_1 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_billing_1),", + "__actual__regional_stg_billing_1 AS (SELECT * FROM __ref__regional_stg_billing_1),", + "__expected__regional_stg_billing_1 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_billing_1' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_billing_1) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_billing_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_billing_1 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_billing_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_billing_1 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_billing_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_billing_0/test_stg_billing_0.sql": [ + "WITH __source__raw_events_2 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_billing_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 374 AS threshold_0_amount,", + " 'Zürich – depot' AS threshold_1_label", + "FROM __source__raw_events_2 t),", + "__actual__stg_billing_0 AS (SELECT * FROM __ref__stg_billing_0),", + "__expected__stg_billing_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_billing_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_billing_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_billing_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_billing_0 EXCEPT SELECT id, status FROM __expected__stg_billing_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_billing_0 EXCEPT SELECT id, status FROM __actual__stg_billing_0) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_3.banded_amounts": { + "database": null, + "schema": "main", + "name": "banded_amounts", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/analysis/banded_amounts.sql", + "original_file_path": "models/analysis/banded_amounts.sql", + "unique_id": "model.generated_3.banded_amounts", + "fqn": [ + "generated_3", + "models", + "analysis", + "banded_amounts" + ], + "alias": "banded_amounts", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amount bands from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.banded_amounts", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.table_fn__amount_bands" + ] + } + }, + "model.generated_3.checked_stg_billing_1": { + "database": null, + "schema": "main", + "name": "checked_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/analysis/checked_stg_billing_1.sql", + "original_file_path": "models/analysis/checked_stg_billing_1.sql", + "unique_id": "model.generated_3.checked_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "analysis", + "checked_stg_billing_1" + ], + "alias": "checked_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_billing_1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.checked_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.regional_stg_billing_1": { + "database": null, + "schema": "main", + "name": "regional_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/analysis/regional_stg_billing_1.sql", + "original_file_path": "models/analysis/regional_stg_billing_1.sql", + "unique_id": "model.generated_3.regional_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "analysis", + "regional_stg_billing_1" + ], + "alias": "regional_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_billing_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.regional_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.scaled_stg_billing_1": { + "database": null, + "schema": "main", + "name": "scaled_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/analysis/scaled_stg_billing_1.sql", + "original_file_path": "models/analysis/scaled_stg_billing_1.sql", + "unique_id": "model.generated_3.scaled_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "analysis", + "scaled_stg_billing_1" + ], + "alias": "scaled_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Scaled amounts of stg_billing_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.scaled_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.scaled_amount", + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.billing_summary_0": { + "database": null, + "schema": "main", + "name": "billing_summary_0", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/billing/marts/billing_summary_0.sql", + "original_file_path": "models/billing/marts/billing_summary_0.sql", + "unique_id": "model.generated_3.billing_summary_0", + "fqn": [ + "generated_3", + "models", + "billing", + "marts", + "billing_summary_0" + ], + "alias": "billing_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of billing activity 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.billing_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1", + "model.generated_3.stg_billing_0" + ] + } + }, + "model.generated_3.billing_summary_1": { + "database": null, + "schema": "main", + "name": "billing_summary_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/billing/marts/billing_summary_1.sql", + "original_file_path": "models/billing/marts/billing_summary_1.sql", + "unique_id": "model.generated_3.billing_summary_1", + "fqn": [ + "generated_3", + "models", + "billing", + "marts", + "billing_summary_1" + ], + "alias": "billing_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.billing_summary_1' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.billing_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of billing activity 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.billing_summary_1' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "name": "record_refresh", + "relative_path": "models/billing/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Zürich – depot" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.billing_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.billing_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.stg_billing_0": { + "database": null, + "schema": "main", + "name": "stg_billing_0", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/billing/staging/stg_billing_0.sql", + "original_file_path": "models/billing/staging/stg_billing_0.sql", + "unique_id": "model.generated_3.stg_billing_0", + "fqn": [ + "generated_3", + "models", + "billing", + "staging", + "stg_billing_0" + ], + "alias": "stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged billing events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_3.raw_events_2" + ] + } + }, + "model.generated_3.stg_billing_1": { + "database": null, + "schema": "main", + "name": "stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/billing/staging/stg_billing_1.sql", + "original_file_path": "models/billing/staging/stg_billing_1.sql", + "unique_id": "model.generated_3.stg_billing_1", + "fqn": [ + "generated_3", + "models", + "billing", + "staging", + "stg_billing_1" + ], + "alias": "stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged billing events 1 (Zürich – depot)", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_3.raw_events_2" + ] + } + }, + "model.generated_3.batched_watermark_stg_billing_1": { + "database": null, + "schema": "main", + "name": "batched_watermark_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/features/batched_watermark_stg_billing_1.sql", + "original_file_path": "models/features/batched_watermark_stg_billing_1.sql", + "unique_id": "model.generated_3.batched_watermark_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "features", + "batched_watermark_stg_billing_1" + ], + "alias": "batched_watermark_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched watermark totals of stg_billing_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.batched_watermark_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.hooked_stg_billing_1": { + "database": null, + "schema": "main", + "name": "hooked_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/features/hooked_stg_billing_1.sql", + "original_file_path": "models/features/hooked_stg_billing_1.sql", + "unique_id": "model.generated_3.hooked_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "features", + "hooked_stg_billing_1" + ], + "alias": "hooked_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Hooked copy of stg_billing_1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "python", + "name": "note_refresh", + "kwargs": { + "channel": "東京 warehouse" + }, + "relative_path": "models/features/_sqlbuild/_hooks/python/notify.py", + "definition_hash": "55440ff19f0c4f231ad57d453227a3c9d584b81234ee4b3338a39ccdf59814a8", + "version_hash": "03b4f786f8ab2736e5be2e4de5016bd16ea44d84beca000ec2a53a397e503eb6" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.hooked_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.kept_stg_billing_1": { + "database": null, + "schema": "main", + "name": "kept_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/features/kept_stg_billing_1.sql", + "original_file_path": "models/features/kept_stg_billing_1.sql", + "unique_id": "model.generated_3.kept_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "features", + "kept_stg_billing_1" + ], + "alias": "kept_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Statuses kept from stg_billing_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.kept_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.audited_event_totals": { + "database": null, + "schema": "main", + "name": "audited_event_totals", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/audited_event_totals.sql", + "original_file_path": "models/rendering/audited_event_totals.sql", + "unique_id": "model.generated_3.audited_event_totals", + "fqn": [ + "generated_3", + "models", + "rendering", + "audited_event_totals" + ], + "alias": "audited_event_totals", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Totals of the audited events per channel", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.audited_event_totals", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_3.audited_events", + "seed.generated_3.channel_codes" + ] + } + }, + "model.generated_3.configured_stg_billing_1": { + "database": null, + "schema": "main", + "name": "configured_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/configured_stg_billing_1.sql", + "original_file_path": "models/rendering/configured_stg_billing_1.sql", + "unique_id": "model.generated_3.configured_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "rendering", + "configured_stg_billing_1" + ], + "alias": "configured_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "development" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "development" + ], + "description": "Configured copy of stg_billing_1 (réglé)", + "columns": { + "id": { + "name": "id", + "description": "Row key", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Montant réglé", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.configured_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.interpolated_stg_billing_0": { + "database": null, + "schema": "main", + "name": "interpolated_stg_billing_0", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/interpolated_stg_billing_0.sql", + "original_file_path": "models/rendering/interpolated_stg_billing_0.sql", + "unique_id": "model.generated_3.interpolated_stg_billing_0", + "fqn": [ + "generated_3", + "models", + "rendering", + "interpolated_stg_billing_0" + ], + "alias": "interpolated_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.interpolated_stg_billing_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'refreshed ' || 'main.interpolated_stg_billing_0' AS note", + "transaction": true, + "index": 1 + }, + { + "sql": "SELECT 'dev' AS target, 'interpolated_stg_billing_0' AS model", + "transaction": true, + "index": 2 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Interpolated copy of stg_billing_0", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.interpolated_stg_billing_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "announce_refresh", + "relative_path": "models/rendering/_sqlbuild/_hooks/sql/announce_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Announce one refreshed relation" + }, + { + "type": "sql", + "statement": "SELECT 'refreshed ' || 'main.interpolated_stg_billing_0' AS note" + }, + { + "type": "sql", + "statement": "SELECT 'dev' AS target, 'interpolated_stg_billing_0' AS model" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.interpolated_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_0" + ] + } + }, + "model.generated_3.legacy_event_ids": { + "database": null, + "schema": "main", + "name": "legacy_event_ids", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/legacy_event_ids.sql", + "original_file_path": "models/rendering/legacy_event_ids.sql", + "unique_id": "model.generated_3.legacy_event_ids", + "fqn": [ + "generated_3", + "models", + "rendering", + "legacy_event_ids" + ], + "alias": "legacy_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids read through a macro-generated reference", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.legacy_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.policy_stg_billing_1": { + "database": null, + "schema": "main", + "name": "policy_stg_billing_1", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/policy_stg_billing_1.sql", + "original_file_path": "models/rendering/policy_stg_billing_1.sql", + "unique_id": "model.generated_3.policy_stg_billing_1", + "fqn": [ + "generated_3", + "models", + "rendering", + "policy_stg_billing_1" + ], + "alias": "policy_stg_billing_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Policy-filtered copy of stg_billing_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.policy_stg_billing_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_1" + ] + } + }, + "model.generated_3.windowed_stg_billing_0": { + "database": null, + "schema": "main", + "name": "windowed_stg_billing_0", + "resource_type": "model", + "package_name": "generated_3", + "path": "models/rendering/windowed_stg_billing_0.sql", + "original_file_path": "models/rendering/windowed_stg_billing_0.sql", + "unique_id": "model.generated_3.windowed_stg_billing_0", + "fqn": [ + "generated_3", + "models", + "rendering", + "windowed_stg_billing_0" + ], + "alias": "windowed_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "windowed_copy", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Runtime-windowed copy of stg_billing_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.windowed_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_3.stg_billing_0" + ] + } + }, + "seed.generated_3.channel_codes": { + "database": null, + "schema": "main", + "name": "channel_codes", + "resource_type": "seed", + "package_name": "generated_3", + "path": "seeds/channel_codes.csv", + "original_file_path": "seeds/channel_codes.csv", + "unique_id": "seed.generated_3.channel_codes", + "fqn": [ + "generated_3", + "seeds", + "channel_codes" + ], + "alias": "channel_codes", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Channel codes with seed audits.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.channel_codes", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.generated_3.audited_events": { + "database": null, + "schema": "", + "name": "audited_events", + "resource_type": "source", + "package_name": "generated_3", + "path": "sources/audited.yml", + "original_file_path": "sources/audited.yml", + "unique_id": "source.generated_3.audited_events", + "fqn": [ + "generated_3", + "audited_events" + ], + "source_name": "audited_events", + "source_description": "", + "loader": "", + "identifier": "audited_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Events with source audits.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_3.configured_events": { + "database": null, + "schema": "", + "name": "configured_events", + "resource_type": "source", + "package_name": "generated_3", + "path": "sources/configured.yml", + "original_file_path": "sources/configured.yml", + "unique_id": "source.generated_3.configured_events", + "fqn": [ + "generated_3", + "configured_events" + ], + "source_name": "configured_events", + "source_description": "", + "loader": "", + "identifier": "configured_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Configured feed events", + "columns": { + "id": { + "name": "id", + "description": "Key id", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "owner": "orders team" + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_3.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_3", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_3.raw_events_0", + "fqn": [ + "generated_3", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_3.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_3", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_3.raw_events_1", + "fqn": [ + "generated_3", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_3.raw_events_2": { + "database": null, + "schema": "", + "name": "raw_events_2", + "resource_type": "source", + "package_name": "generated_3", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_3.raw_events_2", + "fqn": [ + "generated_3", + "raw_events_2" + ], + "source_name": "raw_events_2", + "source_description": "", + "loader": "", + "identifier": "raw_events_2", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 2.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_3.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_3.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'east'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/billing/marts/_sqlbuild/_macros/adjust_0.py", + "original_file_path": "models/billing/marts/_sqlbuild/_macros/adjust_0.py", + "unique_id": "macro.generated_3.adjust_0", + "macro_sql": "def adjust_0(expression: str) -> str:\n \"\"\"Offset an amount.\"\"\"\n return f\"({expression} + 0 + 1)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/billing/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/billing/staging/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/billing/staging/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_3.adjust_1", + "macro_sql": "def adjust_1(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/billing/staging" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.legacy_events": { + "name": "legacy_events", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/rendering/_sqlbuild/_macros/legacy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/legacy.py", + "unique_id": "macro.generated_3.legacy_events", + "macro_sql": "def legacy_events() -> str:\n \"\"\"Return a staged relation the way a migrated project wrote it.\"\"\"\n return '__ref(\"stg_billing_1\")'\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.refresh_note": { + "name": "refresh_note", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/rendering/_sqlbuild/_macros/notes.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/notes.py", + "unique_id": "macro.generated_3.refresh_note", + "macro_sql": "def refresh_note(relation: str) -> str:\n \"\"\"Describe one refreshed relation.\"\"\"\n return f\"'refreshed ' || '{relation}'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.channel_label": { + "name": "channel_label", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_3.channel_label", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.minimum_amount_filter": { + "name": "minimum_amount_filter", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_3.minimum_amount_filter", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.with_deployment": { + "name": "with_deployment", + "resource_type": "macro", + "package_name": "generated_3", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_3.with_deployment", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3.doubled": { + "name": "doubled", + "resource_type": "macro", + "package_name": "generated_3", + "path": "tests/unit/_macros/scaling.py", + "original_file_path": "tests/unit/_macros/scaling.py", + "unique_id": "macro.generated_3.doubled", + "macro_sql": "def doubled(expression: str) -> str:\n \"\"\"Double an amount.\"\"\"\n return f\"({expression} * 2)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_3__sqlbuild_hooks", + "path": "models/billing/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "original_file_path": "models/billing/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_3__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_3__sqlbuild_hooks.announce_refresh": { + "name": "announce_refresh", + "resource_type": "macro", + "package_name": "generated_3__sqlbuild_hooks", + "path": "models/rendering/_sqlbuild/_hooks/sql/announce_refresh.sql", + "original_file_path": "models/rendering/_sqlbuild/_hooks/sql/announce_refresh.sql", + "unique_id": "macro.generated_3__sqlbuild_hooks.announce_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Announce one refreshed relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "announce_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_3.banded_amounts": [ + "model.generated_3.table_fn__amount_bands" + ], + "model.generated_3.checked_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.regional_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.scaled_stg_billing_1": [ + "model.generated_3.scaled_amount", + "model.generated_3.stg_billing_1" + ], + "model.generated_3.billing_summary_0": [ + "model.generated_3.stg_billing_1", + "model.generated_3.stg_billing_0" + ], + "model.generated_3.billing_summary_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.stg_billing_0": [ + "source.generated_3.raw_events_2" + ], + "model.generated_3.stg_billing_1": [ + "source.generated_3.raw_events_2" + ], + "model.generated_3.batched_watermark_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.hooked_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.kept_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.audited_event_totals": [ + "source.generated_3.audited_events", + "seed.generated_3.channel_codes" + ], + "model.generated_3.configured_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.interpolated_stg_billing_0": [ + "model.generated_3.stg_billing_0" + ], + "model.generated_3.legacy_event_ids": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.policy_stg_billing_1": [ + "model.generated_3.stg_billing_1" + ], + "model.generated_3.windowed_stg_billing_0": [ + "model.generated_3.stg_billing_0" + ], + "source.generated_3.audited_events": [], + "source.generated_3.configured_events": [], + "source.generated_3.raw_events_0": [], + "source.generated_3.raw_events_1": [], + "source.generated_3.raw_events_2": [], + "seed.generated_3.channel_codes": [], + "model.generated_3.configured_label": [], + "model.generated_3.scaled_amount": [], + "model.generated_3.table_fn__amount_bands": [ + "model.generated_3.stg_billing_1" + ] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/4.json b/tests/goldens/compiler/seed/4.json new file mode 100644 index 0000000000..c97add18f8 --- /dev/null +++ b/tests/goldens/compiler/seed/4.json @@ -0,0 +1,3131 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/configured_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"configured_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN ('1')", + "" + ], + "audits/generic/configured_stg_support_0/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'shipped')", + "" + ], + "audits/generic/configured_stg_support_0/configured_amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE amount < -30", + "" + ], + "audits/generic/configured_stg_support_0/configured_id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_stg_support_0/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/guarded_stg_support_0/amount_at_least__amount.sql": [ + "SELECT *", + "FROM __ref(\"guarded_stg_support_0\")", + "WHERE amount < 0", + "" + ], + "audits/generic/shaped_stg_support_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"shaped_stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_support_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/support_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"support_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/singular/support_summary_1_matches.sql": [ + "SELECT a.id", + "FROM __ref(\"support_summary_1\") a", + "LEFT JOIN __ref(\"support_summary_0\") b ON a.id = b.id", + "WHERE b.id IS NULL", + "" + ], + "functions/sql/configured_label.sql": [ + "CREATE OR REPLACE MACRO ci_checks.configured_label(raw_status) AS (", + "UPPER(raw_status)", + ")", + "" + ], + "models/analysis/combined_stg_support_0.sql": [ + "WITH recent AS (", + " SELECT id, created_at FROM __ref(\"stg_support_0\") WHERE amount > 0", + "),", + "older AS (", + " SELECT id, created_at FROM __ref(\"stg_support_0\")", + ")", + "SELECT id, created_at FROM recent", + "UNION ALL", + "SELECT id, created_at FROM older", + "" + ], + "models/analysis/every_open_event.sql": [ + "SELECT *", + "FROM __source(\"open_events\")", + "" + ], + "models/analysis/every_raw_events_0.sql": [ + "SELECT *", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/every_stg_support_0.sql": [ + "SELECT *", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/passed_stg_support_0.sql": [ + "WITH passthrough AS (", + " SELECT id, created_at FROM __ref(\"stg_support_0\")", + ")", + "SELECT id, created_at", + "FROM passthrough", + "" + ], + "models/analysis/pivot_input_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR) AS status, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/pivoted_stg_support_0.sql": [ + "PIVOT __ref(\"pivot_input_stg_support_0\")", + "ON status", + "USING MAX(amount)", + "GROUP BY id", + "" + ], + "models/analysis/quoted_stg_support_0.sql": [ + "SELECT \"ID\" AS \"OrderKey\", \"Amount\", \"Status\" AS \"Status\"", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/regional_stg_support_0.sql": [ + "SELECT id, amount, 'north' AS region", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/typed_stg_support_0.sql": [ + "SELECT id, amount * 2 AS doubled_amount, CAST(status AS VARCHAR) AS status_text,", + " created_at, NULL AS missing_note", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/unanalysed_stg_support_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_0\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/features/append_stg_support_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/batched_rolling_window_stg_support_0.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_support_0\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/guarded_stg_support_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/product_labels.sql": [ + "SELECT id, label", + "FROM __source(\"loaded_products\")", + "" + ], + "models/features/shaped_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/timestamp_history_stg_support_0.sql": [ + "SELECT id, status, created_at", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/rendering/bounded_stg_support_0.sql": [ + "SELECT id, amount, created_at", + "FROM __ref(\"stg_support_0\")", + "WHERE created_at >= __cursor_start()", + " AND created_at < __cursor_end()", + "" + ], + "models/rendering/configured_stg_support_0.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/rendering/latest_raw_events_0.sql": [ + "SELECT id, amount", + "FROM (SELECT id, amount FROM __source(\"raw_events_0\") ORDER BY id DESC LIMIT 2) AS latest", + "" + ], + "models/rendering/policy_stg_support_0.sql": [ + "SELECT id, amount, ('web' || '/ci/generated_duckdb/west' || '@web-orders') AS channel,", + " 1 AS minimum_amount,", + " 'store' AS fallback_channel", + "FROM __ref(\"stg_support_0\")", + "WHERE amount >= 1", + "" + ], + "models/rendering/unioned_event_ids.sql": [ + "SELECT id", + "FROM (SELECT id FROM __ref(\"stg_support_0\") UNION ALL SELECT id FROM __ref(\"stg_support_0\")) AS unioned", + "" + ], + "models/support/marts/support_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount,", + " j1.label AS lookup_label_1", + "FROM __ref(\"stg_support_0\") t", + "LEFT JOIN __seed(\"lookup_1\") j1 ON t.id = j1.id", + "" + ], + "models/support/marts/support_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount,", + " j1.label AS lookup_label_1,", + " '東京 warehouse' AS site_label", + "FROM __ref(\"stg_support_0\") t", + "LEFT JOIN __seed(\"lookup_0\") j1 ON t.id = j1.id", + "WHERE t.status <> 'returned ✓'", + "" + ], + "models/support/marts/support_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_1_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_2_amount,", + " j1.label AS lookup_label_1,", + " '東京 warehouse' AS site_label", + "FROM __ref(\"stg_support_0\") t", + "LEFT JOIN __seed(\"lookup_1\") j1 ON t.id = j1.id", + "" + ], + "models/support/staging/stg_support_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_2_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "tests/regional_stg_support_0/test_regional_stg_support_0.sql": [ + "WITH __ref__stg_support_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_support_0 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_support_0),", + "__actual__regional_stg_support_0 AS (SELECT * FROM __ref__regional_stg_support_0),", + "__expected__regional_stg_support_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_support_0 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_support_0 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_support_0/test_stg_support_0.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_2_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_support_0 EXCEPT SELECT id, status FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_support_0 EXCEPT SELECT id, status FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__labelled.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(2.25 AS DOUBLE) AS amount,", + " '東京 warehouse' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_2_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__placed.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(1.5 AS DOUBLE) AS amount,", + " 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_2_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_4.combined_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "combined_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/combined_stg_support_0.sql", + "original_file_path": "models/analysis/combined_stg_support_0.sql", + "unique_id": "model.generated_4.combined_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "combined_stg_support_0" + ], + "alias": "combined_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Recent and older rows of stg_support_0 and stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.combined_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.every_open_event": { + "database": null, + "schema": "ci_checks", + "name": "every_open_event", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/every_open_event.sql", + "original_file_path": "models/analysis/every_open_event.sql", + "unique_id": "model.generated_4.every_open_event", + "fqn": [ + "generated_4", + "models", + "analysis", + "every_open_event" + ], + "alias": "every_open_event", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of an open source", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_open_event", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_4.open_events" + ] + } + }, + "model.generated_4.every_raw_events_0": { + "database": null, + "schema": "ci_checks", + "name": "every_raw_events_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/every_raw_events_0.sql", + "original_file_path": "models/analysis/every_raw_events_0.sql", + "unique_id": "model.generated_4.every_raw_events_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "every_raw_events_0" + ], + "alias": "every_raw_events_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of raw_events_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_raw_events_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_4.raw_events_0" + ] + } + }, + "model.generated_4.every_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "every_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/every_stg_support_0.sql", + "original_file_path": "models/analysis/every_stg_support_0.sql", + "unique_id": "model.generated_4.every_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "every_stg_support_0" + ], + "alias": "every_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.passed_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "passed_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/passed_stg_support_0.sql", + "original_file_path": "models/analysis/passed_stg_support_0.sql", + "unique_id": "model.generated_4.passed_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "passed_stg_support_0" + ], + "alias": "passed_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Columns of stg_support_0 passed through a CTE", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.passed_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.pivot_input_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivot_input_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/pivot_input_stg_support_0.sql", + "original_file_path": "models/analysis/pivot_input_stg_support_0.sql", + "unique_id": "model.generated_4.pivot_input_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "pivot_input_stg_support_0" + ], + "alias": "pivot_input_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted pivot input from stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivot_input_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.pivoted_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivoted_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/pivoted_stg_support_0.sql", + "original_file_path": "models/analysis/pivoted_stg_support_0.sql", + "unique_id": "model.generated_4.pivoted_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "pivoted_stg_support_0" + ], + "alias": "pivoted_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amounts of stg_support_0 pivoted by status", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivoted_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.pivot_input_stg_support_0" + ] + } + }, + "model.generated_4.quoted_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "quoted_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/quoted_stg_support_0.sql", + "original_file_path": "models/analysis/quoted_stg_support_0.sql", + "unique_id": "model.generated_4.quoted_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "quoted_stg_support_0" + ], + "alias": "quoted_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Quoted identifiers over stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.quoted_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.regional_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "regional_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/regional_stg_support_0.sql", + "original_file_path": "models/analysis/regional_stg_support_0.sql", + "unique_id": "model.generated_4.regional_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "regional_stg_support_0" + ], + "alias": "regional_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.regional_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.typed_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "typed_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/typed_stg_support_0.sql", + "original_file_path": "models/analysis/typed_stg_support_0.sql", + "unique_id": "model.generated_4.typed_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "typed_stg_support_0" + ], + "alias": "typed_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Typed and untyped outputs of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.typed_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.unanalysed_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "unanalysed_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/analysis/unanalysed_stg_support_0.sql", + "original_file_path": "models/analysis/unanalysed_stg_support_0.sql", + "unique_id": "model.generated_4.unanalysed_stg_support_0", + "fqn": [ + "generated_4", + "models", + "analysis", + "unanalysed_stg_support_0" + ], + "alias": "unanalysed_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_support_0 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unanalysed_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.append_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "append_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/append_stg_support_0.sql", + "original_file_path": "models/features/append_stg_support_0.sql", + "unique_id": "model.generated_4.append_stg_support_0", + "fqn": [ + "generated_4", + "models", + "features", + "append_stg_support_0" + ], + "alias": "append_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "append", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental append copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.append_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.batched_rolling_window_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "batched_rolling_window_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/batched_rolling_window_stg_support_0.sql", + "original_file_path": "models/features/batched_rolling_window_stg_support_0.sql", + "unique_id": "model.generated_4.batched_rolling_window_stg_support_0", + "fqn": [ + "generated_4", + "models", + "features", + "batched_rolling_window_stg_support_0" + ], + "alias": "batched_rolling_window_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched rolling_window totals of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.batched_rolling_window_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.guarded_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "guarded_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/guarded_stg_support_0.sql", + "original_file_path": "models/features/guarded_stg_support_0.sql", + "unique_id": "model.generated_4.guarded_stg_support_0", + "fqn": [ + "generated_4", + "models", + "features", + "guarded_stg_support_0" + ], + "alias": "guarded_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Generic-audited copy of stg_support_0", + "columns": { + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.guarded_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.product_labels": { + "database": null, + "schema": "ci_checks", + "name": "product_labels", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/product_labels.sql", + "original_file_path": "models/features/product_labels.sql", + "unique_id": "model.generated_4.product_labels", + "fqn": [ + "generated_4", + "models", + "features", + "product_labels" + ], + "alias": "product_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Product labels from the loader", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.product_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_4.loaded_products" + ] + } + }, + "model.generated_4.shaped_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "shaped_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/shaped_stg_support_0.sql", + "original_file_path": "models/features/shaped_stg_support_0.sql", + "unique_id": "model.generated_4.shaped_stg_support_0", + "fqn": [ + "generated_4", + "models", + "features", + "shaped_stg_support_0" + ], + "alias": "shaped_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Schema-shaped copy of stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.shaped_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.timestamp_history_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "timestamp_history_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/features/timestamp_history_stg_support_0.sql", + "original_file_path": "models/features/timestamp_history_stg_support_0.sql", + "unique_id": "model.generated_4.timestamp_history_stg_support_0", + "fqn": [ + "generated_4", + "models", + "features", + "timestamp_history_stg_support_0" + ], + "alias": "timestamp_history_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "snapshot", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Timestamp history of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.timestamp_history_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.bounded_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "bounded_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/rendering/bounded_stg_support_0.sql", + "original_file_path": "models/rendering/bounded_stg_support_0.sql", + "unique_id": "model.generated_4.bounded_stg_support_0", + "fqn": [ + "generated_4", + "models", + "rendering", + "bounded_stg_support_0" + ], + "alias": "bounded_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Cursor-bounded copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.bounded_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.configured_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "configured_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/rendering/configured_stg_support_0.sql", + "original_file_path": "models/rendering/configured_stg_support_0.sql", + "unique_id": "model.generated_4.configured_stg_support_0", + "fqn": [ + "generated_4", + "models", + "rendering", + "configured_stg_support_0" + ], + "alias": "configured_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "release" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "release" + ], + "description": "Configured copy of stg_support_0 (réglé)", + "columns": { + "id": { + "name": "id", + "description": "Row key", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Montant réglé", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.configured_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.latest_raw_events_0": { + "database": null, + "schema": "ci_checks", + "name": "latest_raw_events_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/rendering/latest_raw_events_0.sql", + "original_file_path": "models/rendering/latest_raw_events_0.sql", + "unique_id": "model.generated_4.latest_raw_events_0", + "fqn": [ + "generated_4", + "models", + "rendering", + "latest_raw_events_0" + ], + "alias": "latest_raw_events_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Newest rows of raw_events_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.latest_raw_events_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_4.raw_events_0" + ] + } + }, + "model.generated_4.policy_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "policy_stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/rendering/policy_stg_support_0.sql", + "original_file_path": "models/rendering/policy_stg_support_0.sql", + "unique_id": "model.generated_4.policy_stg_support_0", + "fqn": [ + "generated_4", + "models", + "rendering", + "policy_stg_support_0" + ], + "alias": "policy_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Policy-filtered copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.policy_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.unioned_event_ids": { + "database": null, + "schema": "ci_checks", + "name": "unioned_event_ids", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/rendering/unioned_event_ids.sql", + "original_file_path": "models/rendering/unioned_event_ids.sql", + "unique_id": "model.generated_4.unioned_event_ids", + "fqn": [ + "generated_4", + "models", + "rendering", + "unioned_event_ids" + ], + "alias": "unioned_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids from two staged relations", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unioned_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0" + ] + } + }, + "model.generated_4.support_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/support/marts/support_summary_0.sql", + "original_file_path": "models/support/marts/support_summary_0.sql", + "unique_id": "model.generated_4.support_summary_0", + "fqn": [ + "generated_4", + "models", + "support", + "marts", + "support_summary_0" + ], + "alias": "support_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "support", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "support", + "marts" + ], + "description": "Summary of support activity 0 (東京 warehouse)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "name": "record_refresh", + "relative_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "naïve résumé" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_1" + ] + } + }, + "model.generated_4.support_summary_1": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_1", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/support/marts/support_summary_1.sql", + "original_file_path": "models/support/marts/support_summary_1.sql", + "unique_id": "model.generated_4.support_summary_1", + "fqn": [ + "generated_4", + "models", + "support", + "marts", + "support_summary_1" + ], + "alias": "support_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "support", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "support", + "marts" + ], + "description": "Summary of support activity 1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_0" + ] + } + }, + "model.generated_4.support_summary_2": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_2", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/support/marts/support_summary_2.sql", + "original_file_path": "models/support/marts/support_summary_2.sql", + "unique_id": "model.generated_4.support_summary_2", + "fqn": [ + "generated_4", + "models", + "support", + "marts", + "support_summary_2" + ], + "alias": "support_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "support", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "support", + "marts" + ], + "description": "Summary of support activity 2 (café ☕ counter)", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_1" + ] + } + }, + "model.generated_4.stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_support_0", + "resource_type": "model", + "package_name": "generated_4", + "path": "models/support/staging/stg_support_0.sql", + "original_file_path": "models/support/staging/stg_support_0.sql", + "unique_id": "model.generated_4.stg_support_0", + "fqn": [ + "generated_4", + "models", + "support", + "staging", + "stg_support_0" + ], + "alias": "stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged support events 0 (naïve résumé)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_4.raw_events_0" + ] + } + }, + "seed.generated_4.lookup_0": { + "database": null, + "schema": "ci_checks", + "name": "lookup_0", + "resource_type": "seed", + "package_name": "generated_4", + "path": "seeds/lookup_0.csv", + "original_file_path": "seeds/lookup_0.csv", + "unique_id": "seed.generated_4.lookup_0", + "fqn": [ + "generated_4", + "seeds", + "lookup_0" + ], + "alias": "lookup_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.lookup_0", + "root_path": null, + "depends_on": { + "macros": [] + } + }, + "seed.generated_4.lookup_1": { + "database": null, + "schema": "ci_checks", + "name": "lookup_1", + "resource_type": "seed", + "package_name": "generated_4", + "path": "seeds/lookup_1.csv", + "original_file_path": "seeds/lookup_1.csv", + "unique_id": "seed.generated_4.lookup_1", + "fqn": [ + "generated_4", + "seeds", + "lookup_1" + ], + "alias": "lookup_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "seed", + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + }, + "delimiter": ",", + "quote_columns": null + }, + "tags": [], + "description": "Generated lookup 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.lookup_1", + "root_path": null, + "depends_on": { + "macros": [] + } + } + }, + "sources": { + "source.generated_4.configured_events": { + "database": null, + "schema": "", + "name": "configured_events", + "resource_type": "source", + "package_name": "generated_4", + "path": "sources/configured.yml", + "original_file_path": "sources/configured.yml", + "unique_id": "source.generated_4.configured_events", + "fqn": [ + "generated_4", + "configured_events" + ], + "source_name": "configured_events", + "source_description": "", + "loader": "", + "identifier": "configured_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Configured feed events", + "columns": { + "id": { + "name": "id", + "description": "Key id", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "owner": "orders team" + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_4.loaded_products": { + "database": null, + "schema": "ci_checks", + "name": "loaded_products", + "resource_type": "source", + "package_name": "generated_4", + "path": "sources/managed.yml", + "original_file_path": "sources/managed.yml", + "unique_id": "source.generated_4.loaded_products", + "fqn": [ + "generated_4", + "loaded_products" + ], + "source_name": "loaded_products", + "source_description": "", + "loader": "", + "identifier": "loaded_products", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Products loaded by a project loader.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "loaded_products", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_4.open_events": { + "database": null, + "schema": "", + "name": "open_events", + "resource_type": "source", + "package_name": "generated_4", + "path": "sources/open.yml", + "original_file_path": "sources/open.yml", + "unique_id": "source.generated_4.open_events", + "fqn": [ + "generated_4", + "open_events" + ], + "source_name": "open_events", + "source_description": "", + "loader": "", + "identifier": "open_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Events whose columns are only known to the warehouse.", + "columns": {}, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_4.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_4", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_4.raw_events_0", + "fqn": [ + "generated_4", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_4.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_4.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'north'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.channel_label": { + "name": "channel_label", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_4.channel_label", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.minimum_amount_filter": { + "name": "minimum_amount_filter", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_4.minimum_amount_filter", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.with_deployment": { + "name": "with_deployment", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/rendering/_sqlbuild/_macros/policy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/policy.py", + "unique_id": "macro.generated_4.with_deployment", + "macro_sql": "import os\n\n\ndef minimum_amount_filter(ctx, column: str) -> str:\n \"\"\"Keep rows at or above the configured minimum amount.\"\"\"\n if ctx.constants[\"minimum_render_amount\"] is None:\n return \"TRUE\"\n return f\"{column} >= {ctx.render_constant('minimum_render_amount')}\"\n\n\ndef channel_label(ctx) -> str:\n \"\"\"Label rows with the web channel, target and adapter.\"\"\"\n channel = ctx.render_enum_member(enum_name=\"render_channel\", member_name=\"WEB\")\n region = ctx.vars[\"region\"]\n return f\"{channel} || '/{ctx.target_name}/{ctx.adapter_name}/{region}'\"\n\n\ndef with_deployment(expression: str) -> str:\n \"\"\"Suffix an expression with the deployment channel from the environment.\"\"\"\n channel = os.environ.get(\"SQB_DIFFERENTIAL_CHANNEL\", \"none\")\n return f\"({expression} || '@{channel}')\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.latest_rows": { + "name": "latest_rows", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_4.latest_rows", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.union_ids": { + "name": "union_ids", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_4.union_ids", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/_sqlbuild/macros/adjust_2.py", + "original_file_path": "models/support/_sqlbuild/macros/adjust_2.py", + "unique_id": "macro.generated_4.adjust_2", + "macro_sql": "def adjust_2_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_2(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_2_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_4.adjust_2_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/support" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_2_round": { + "name": "adjust_2_round", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/_sqlbuild/macros/adjust_2.py", + "original_file_path": "models/support/_sqlbuild/macros/adjust_2.py", + "unique_id": "macro.generated_4.adjust_2_round", + "macro_sql": "def adjust_2_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_2(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_2_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/support" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "original_file_path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "unique_id": "macro.generated_4.adjust_0", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_4.adjust_0_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/support/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_0_round": { + "name": "adjust_0_round", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "original_file_path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "unique_id": "macro.generated_4.adjust_0_round", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/support/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/marts/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/support/marts/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_4.adjust_1", + "macro_sql": "def adjust_1_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_1_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_4.adjust_1_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/support/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4.adjust_1_round": { + "name": "adjust_1_round", + "resource_type": "macro", + "package_name": "generated_4", + "path": "models/support/marts/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/support/marts/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_4.adjust_1_round", + "macro_sql": "def adjust_1_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_1_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/support/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_4__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_4__sqlbuild_hooks", + "path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "original_file_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_4__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_4.combined_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.every_open_event": [ + "source.generated_4.open_events" + ], + "model.generated_4.every_raw_events_0": [ + "source.generated_4.raw_events_0" + ], + "model.generated_4.every_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.passed_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.pivot_input_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.pivoted_stg_support_0": [ + "model.generated_4.pivot_input_stg_support_0" + ], + "model.generated_4.quoted_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.regional_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.typed_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.unanalysed_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.append_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.batched_rolling_window_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.guarded_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.product_labels": [ + "source.generated_4.loaded_products" + ], + "model.generated_4.shaped_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.timestamp_history_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.bounded_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.configured_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.latest_raw_events_0": [ + "source.generated_4.raw_events_0" + ], + "model.generated_4.policy_stg_support_0": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.unioned_event_ids": [ + "model.generated_4.stg_support_0" + ], + "model.generated_4.support_summary_0": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_1" + ], + "model.generated_4.support_summary_1": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_0" + ], + "model.generated_4.support_summary_2": [ + "model.generated_4.stg_support_0", + "seed.generated_4.lookup_1" + ], + "model.generated_4.stg_support_0": [ + "source.generated_4.raw_events_0" + ], + "source.generated_4.configured_events": [], + "source.generated_4.loaded_products": [], + "source.generated_4.open_events": [], + "source.generated_4.raw_events_0": [], + "seed.generated_4.lookup_0": [], + "seed.generated_4.lookup_1": [], + "model.generated_4.configured_label": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/5.json b/tests/goldens/compiler/seed/5.json new file mode 100644 index 0000000000..a6ccbc7f30 --- /dev/null +++ b/tests/goldens/compiler/seed/5.json @@ -0,0 +1,48 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro name collision for 'adjust_0': macros/adjust_0.py and macros/duplicate_adjust_0.py" + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Macro name collision for 'adjust_0': macros/adjust_0.py and macros/duplicate_adjust_0.py" + } + ] + }, + { + "label": "plan", + "exit_code": 1, + "diagnostics": [ + "Project discovery START", + "Project assembly START", + "Declaration parsing START", + "Declaration parsing OK ()", + "Python discovery START", + "Python discovery OK ()", + "Project assembly OK ()", + "Project discovery OK ()", + "Compiling project...", + "error[P001]: Macro name collision for 'adjust_0': macros/adjust_0.py and macros/duplicate_adjust_0.py", + "", + "" + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/seed/6.json b/tests/goldens/compiler/seed/6.json new file mode 100644 index 0000000000..98fe263c63 --- /dev/null +++ b/tests/goldens/compiler/seed/6.json @@ -0,0 +1,3354 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-select", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-no-analysis", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-rich-lineage", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/audited_stg_fulfillment_1/id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"audited_stg_fulfillment_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/checked_stg_fulfillment_2/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_fulfillment_2\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_fulfillment_2/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_fulfillment_2\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_fulfillment_2/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_fulfillment_2\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_fulfillment_2\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/fulfillment_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"fulfillment_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/sales_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"sales_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/shaped_stg_inventory_2/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"shaped_stg_inventory_2\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stated_stg_inventory_2/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"stated_stg_inventory_2\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/stg_fulfillment_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_fulfillment_2/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_fulfillment_2\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_inventory_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_inventory_1\")", + "WHERE id IS NULL", + "" + ], + "functions/python/is_large.sql": [ + "REGISTER PYTHON FUNCTION is_large(DOUBLE) RETURNS BOOLEAN", + "" + ], + "functions/sql/is_placed.sql": [ + "CREATE OR REPLACE MACRO main.is_placed(event_status) AS (", + "event_status = 'placed'", + ")", + "" + ], + "functions/sql/table_fn__events_above.sql": [ + "CREATE OR REPLACE MACRO main.table_fn__events_above(p_minimum) AS TABLE", + "SELECT id, amount", + "FROM __ref(\"stg_sales_0\")", + "WHERE amount > p_minimum", + "" + ], + "models/analysis/chain_1_stg_fulfillment_2.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"contracted_stg_fulfillment_2\")", + "" + ], + "models/analysis/chain_2_stg_fulfillment_2.sql": [ + "SELECT id, UPPER(label) AS label, amount", + "FROM __ref(\"chain_1_stg_fulfillment_2\")", + "" + ], + "models/analysis/chain_3_stg_fulfillment_2.sql": [ + "SELECT id, label, amount", + "FROM __ref(\"chain_2_stg_fulfillment_2\")", + "" + ], + "models/analysis/checked_stg_fulfillment_2.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_fulfillment_2\")", + "" + ], + "models/analysis/contracted_stg_fulfillment_2.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR(18)) AS label,", + " amount", + "FROM __source(\"raw_events_0\")", + "" + ], + "models/analysis/cte_facts_stg_fulfillment_1.sql": [ + "WITH base AS (", + " SELECT id, CAST(amount AS DECIMAL(12, 2)) AS amount, 'event' AS kind,", + " COALESCE(status, 'unknown') AS status", + " FROM __ref(\"stg_fulfillment_1\")", + " WHERE id IS NOT NULL", + ")", + "SELECT id + 0 AS id, amount, UPPER(kind) AS kind, UPPER(status) AS status", + "FROM base", + "" + ], + "models/analysis/regional_stg_fulfillment_0.sql": [ + "SELECT id, amount, 'north' AS region", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/features/audited_stg_fulfillment_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_fulfillment_1\")", + "" + ], + "models/features/batched_rolling_window_stg_sales_0.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_sales_0\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/check_history_stg_inventory_1.sql": [ + "SELECT id, status, amount", + "FROM __ref(\"stg_inventory_1\")", + "" + ], + "models/features/copied_stg_fulfillment_2.sql": [ + "SELECT id, status", + "FROM __ref(\"stg_fulfillment_2\")", + "" + ], + "models/features/flagged_stg_sales_0.sql": [ + "SELECT id, __udf(\"is_placed\")(status) AS is_placed,", + " __udf(\"is_large\")(amount) AS is_large", + "FROM __ref(\"stg_sales_0\")", + "" + ], + "models/features/hooked_stg_inventory_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_inventory_1\")", + "" + ], + "models/features/merge_stg_inventory_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_inventory_0\")", + "" + ], + "models/features/shaped_stg_inventory_2.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status", + "FROM __ref(\"stg_inventory_2\")", + "" + ], + "models/features/spaced_stg_fulfillment_0.sql": [ + "-- Généré pour café ☕ counter", + "SELECT", + "\tid,", + "\t'Ελληνικά orders' AS label, -- étiquette ✓", + "\tamount", + "FROM __ref(\"stg_fulfillment_0\")", + "" + ], + "models/features/taxed_stg_inventory_0.sql": [ + "SELECT id, ROUND(amount * 1.2, 2) AS taxed, ROUND(amount, 1) AS rounded", + "FROM __ref(\"stg_inventory_0\")", + "" + ], + "models/fulfillment/marts/fulfillment_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 3 AS priority,", + " (t.amount + LENGTH('east')) AS adjust_1_amount", + "FROM __ref(\"stg_fulfillment_0\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 3 AS priority,", + " 'Ελληνικά orders' AS threshold_0_label,", + " '東京 warehouse' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/fulfillment/staging/stg_fulfillment_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/inventory/marts/inventory_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_inventory_1\") t", + "WHERE t.status <> '取消'", + "" + ], + "models/inventory/marts/inventory_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_inventory_2\") t", + "" + ], + "models/inventory/staging/stg_inventory_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " '東京 warehouse' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/inventory/staging/stg_inventory_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/inventory/staging/stg_inventory_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount,", + " '東京 warehouse' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/rendering/large_events.sql": [ + "SELECT id, amount", + "FROM __table_fn(\"table_fn__events_above\")(4)", + "" + ], + "models/rendering/stated_stg_inventory_2.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status,", + " CASE WHEN amount >= 9 THEN 'HIGH'", + " ELSE 'LOW' END AS tier", + "FROM __ref(\"stg_inventory_2\")", + "" + ], + "models/sales/marts/sales_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " ROUND(ROUND((t.amount * 2), 2), 2) AS adjust_0_amount", + "FROM __ref(\"stg_sales_0\") t", + "" + ], + "models/sales/marts/sales_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at", + "FROM __ref(\"stg_sales_0\") t", + "LEFT JOIN __ref(\"stg_inventory_1\") j1 ON t.id = j1.id", + "" + ], + "models/sales/staging/stg_sales_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " '東京 warehouse' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "tests/macro doubles_amounts/doubles_amounts.sql": [ + "WITH input_values AS (SELECT 4 AS amount),", + "__actual__macro_doubles_amounts AS (SELECT (amount * 2) AS doubled", + " FROM input_values),", + "__expected__macro_doubles_amounts AS (SELECT 8 AS doubled)", + "SELECT 0 AS step_index, 'macro doubles_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_doubles_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_doubles_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_doubles_amounts EXCEPT SELECT * FROM __expected__macro_doubles_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_doubles_amounts EXCEPT SELECT * FROM __actual__macro_doubles_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/macro taxes_amounts/taxes_amounts.sql": [ + "WITH input_values AS (SELECT 10 AS amount),", + "__actual__macro_taxes_amounts AS (SELECT ROUND(amount * 1.2, 2) AS taxed", + " FROM input_values),", + "__expected__macro_taxes_amounts AS (SELECT 12.0 AS taxed)", + "SELECT 0 AS step_index, 'macro taxes_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_taxes_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_taxes_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_taxes_amounts EXCEPT SELECT * FROM __expected__macro_taxes_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_taxes_amounts EXCEPT SELECT * FROM __actual__macro_taxes_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/regional_stg_fulfillment_0/test_regional_stg_fulfillment_0.sql": [ + "WITH __ref__stg_fulfillment_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__regional_stg_fulfillment_0 AS (SELECT id, amount, 'west' AS region", + "FROM __ref__stg_fulfillment_0),", + "__actual__regional_stg_fulfillment_0 AS (SELECT * FROM __ref__regional_stg_fulfillment_0),", + "__expected__regional_stg_fulfillment_0 AS (SELECT 1 AS id, CAST(4 AS DOUBLE) AS amount, 'west' AS region)", + "SELECT 0 AS step_index, 'regional_stg_fulfillment_0' AS model_name, (SELECT COUNT(*) FROM __actual__regional_stg_fulfillment_0) AS actual_count, (SELECT COUNT(*) FROM __expected__regional_stg_fulfillment_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __actual__regional_stg_fulfillment_0 EXCEPT SELECT id, amount, region FROM __expected__regional_stg_fulfillment_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, amount, region FROM __expected__regional_stg_fulfillment_0 EXCEPT SELECT id, amount, region FROM __actual__regional_stg_fulfillment_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_sales_0/test_stg_sales_0.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_sales_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " '東京 warehouse' AS site_label", + "FROM __source__raw_events_0 t),", + "__actual__stg_sales_0 AS (SELECT * FROM __ref__stg_sales_0),", + "__expected__stg_sales_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_sales_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_sales_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_sales_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_sales_0 EXCEPT SELECT id, status FROM __expected__stg_sales_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_sales_0 EXCEPT SELECT id, status FROM __actual__stg_sales_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/udf detects_placed_events/detects_placed_events.sql": [ + "WITH input_values AS (SELECT 'placed' AS event_status),", + "__actual__udf_detects_placed_events AS (SELECT event_status, main.is_placed(event_status) AS is_placed", + " FROM input_values),", + "__expected__udf_detects_placed_events AS (SELECT 'placed' AS event_status, TRUE AS is_placed)", + "SELECT 0 AS step_index, 'udf detects_placed_events' AS model_name, (SELECT COUNT(*) FROM __actual__udf_detects_placed_events) AS actual_count, (SELECT COUNT(*) FROM __expected__udf_detects_placed_events) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__udf_detects_placed_events EXCEPT SELECT * FROM __expected__udf_detects_placed_events) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__udf_detects_placed_events EXCEPT SELECT * FROM __actual__udf_detects_placed_events) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_6.chain_1_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "chain_1_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/chain_1_stg_fulfillment_2.sql", + "original_file_path": "models/analysis/chain_1_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.chain_1_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "analysis", + "chain_1_stg_fulfillment_2" + ], + "alias": "chain_1_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 1 below the contracted copy of stg_fulfillment_2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_1_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.contracted_stg_fulfillment_2" + ] + } + }, + "model.generated_6.chain_2_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "chain_2_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/chain_2_stg_fulfillment_2.sql", + "original_file_path": "models/analysis/chain_2_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.chain_2_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "analysis", + "chain_2_stg_fulfillment_2" + ], + "alias": "chain_2_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 2 below the contracted copy of stg_fulfillment_2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_2_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.chain_1_stg_fulfillment_2" + ] + } + }, + "model.generated_6.chain_3_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "chain_3_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/chain_3_stg_fulfillment_2.sql", + "original_file_path": "models/analysis/chain_3_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.chain_3_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "analysis", + "chain_3_stg_fulfillment_2" + ], + "alias": "chain_3_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Level 3 below the contracted copy of stg_fulfillment_2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.chain_3_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.chain_2_stg_fulfillment_2" + ] + } + }, + "model.generated_6.checked_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "checked_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/checked_stg_fulfillment_2.sql", + "original_file_path": "models/analysis/checked_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.checked_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "analysis", + "checked_stg_fulfillment_2" + ], + "alias": "checked_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_fulfillment_2", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.checked_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_2" + ] + } + }, + "model.generated_6.contracted_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "contracted_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/contracted_stg_fulfillment_2.sql", + "original_file_path": "models/analysis/contracted_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.contracted_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "analysis", + "contracted_stg_fulfillment_2" + ], + "alias": "contracted_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted copy of raw_events_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR(18)", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.contracted_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.cte_facts_stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "cte_facts_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/cte_facts_stg_fulfillment_1.sql", + "original_file_path": "models/analysis/cte_facts_stg_fulfillment_1.sql", + "unique_id": "model.generated_6.cte_facts_stg_fulfillment_1", + "fqn": [ + "generated_6", + "models", + "analysis", + "cte_facts_stg_fulfillment_1" + ], + "alias": "cte_facts_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted CTE reads of stg_fulfillment_1", + "columns": { + "id": { + "name": "id", + "description": "Recovered id", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Recovered amount", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "kind": { + "name": "kind", + "description": "Recovered kind", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "Recovered status", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.cte_facts_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_1" + ] + } + }, + "model.generated_6.regional_stg_fulfillment_0": { + "database": null, + "schema": "main", + "name": "regional_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/analysis/regional_stg_fulfillment_0.sql", + "original_file_path": "models/analysis/regional_stg_fulfillment_0.sql", + "unique_id": "model.generated_6.regional_stg_fulfillment_0", + "fqn": [ + "generated_6", + "models", + "analysis", + "regional_stg_fulfillment_0" + ], + "alias": "regional_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Regional copy of stg_fulfillment_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.regional_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_0" + ] + } + }, + "model.generated_6.audited_stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "audited_stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/audited_stg_fulfillment_1.sql", + "original_file_path": "models/features/audited_stg_fulfillment_1.sql", + "unique_id": "model.generated_6.audited_stg_fulfillment_1", + "fqn": [ + "generated_6", + "models", + "features", + "audited_stg_fulfillment_1" + ], + "alias": "audited_stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Factory-audited copy of stg_fulfillment_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.audited_stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_1" + ] + } + }, + "model.generated_6.batched_rolling_window_stg_sales_0": { + "database": null, + "schema": "main", + "name": "batched_rolling_window_stg_sales_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/batched_rolling_window_stg_sales_0.sql", + "original_file_path": "models/features/batched_rolling_window_stg_sales_0.sql", + "unique_id": "model.generated_6.batched_rolling_window_stg_sales_0", + "fqn": [ + "generated_6", + "models", + "features", + "batched_rolling_window_stg_sales_0" + ], + "alias": "batched_rolling_window_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched rolling_window totals of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.batched_rolling_window_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_sales_0" + ] + } + }, + "model.generated_6.check_history_stg_inventory_1": { + "database": null, + "schema": "main", + "name": "check_history_stg_inventory_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/check_history_stg_inventory_1.sql", + "original_file_path": "models/features/check_history_stg_inventory_1.sql", + "unique_id": "model.generated_6.check_history_stg_inventory_1", + "fqn": [ + "generated_6", + "models", + "features", + "check_history_stg_inventory_1" + ], + "alias": "check_history_stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "snapshot", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Check history of stg_inventory_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.check_history_stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_1" + ] + } + }, + "model.generated_6.copied_stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "copied_stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/copied_stg_fulfillment_2.sql", + "original_file_path": "models/features/copied_stg_fulfillment_2.sql", + "unique_id": "model.generated_6.copied_stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "features", + "copied_stg_fulfillment_2" + ], + "alias": "copied_stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "copy_table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Custom copy of stg_fulfillment_2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.copied_stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_2" + ] + } + }, + "model.generated_6.flagged_stg_sales_0": { + "database": null, + "schema": "main", + "name": "flagged_stg_sales_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/flagged_stg_sales_0.sql", + "original_file_path": "models/features/flagged_stg_sales_0.sql", + "unique_id": "model.generated_6.flagged_stg_sales_0", + "fqn": [ + "generated_6", + "models", + "features", + "flagged_stg_sales_0" + ], + "alias": "flagged_stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Function-flagged copy of stg_sales_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.flagged_stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.is_placed", + "model.generated_6.is_large", + "model.generated_6.stg_sales_0" + ] + } + }, + "model.generated_6.hooked_stg_inventory_1": { + "database": null, + "schema": "main", + "name": "hooked_stg_inventory_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/hooked_stg_inventory_1.sql", + "original_file_path": "models/features/hooked_stg_inventory_1.sql", + "unique_id": "model.generated_6.hooked_stg_inventory_1", + "fqn": [ + "generated_6", + "models", + "features", + "hooked_stg_inventory_1" + ], + "alias": "hooked_stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Hooked copy of stg_inventory_1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "python", + "name": "note_refresh", + "kwargs": { + "channel": "café ☕ counter" + }, + "relative_path": "models/features/_sqlbuild/_hooks/python/notify.py", + "definition_hash": "55440ff19f0c4f231ad57d453227a3c9d584b81234ee4b3338a39ccdf59814a8", + "version_hash": "03b4f786f8ab2736e5be2e4de5016bd16ea44d84beca000ec2a53a397e503eb6" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.hooked_stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_1" + ] + } + }, + "model.generated_6.merge_stg_inventory_0": { + "database": null, + "schema": "main", + "name": "merge_stg_inventory_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/merge_stg_inventory_0.sql", + "original_file_path": "models/features/merge_stg_inventory_0.sql", + "unique_id": "model.generated_6.merge_stg_inventory_0", + "fqn": [ + "generated_6", + "models", + "features", + "merge_stg_inventory_0" + ], + "alias": "merge_stg_inventory_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "merge", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental merge copy of stg_inventory_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.merge_stg_inventory_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_0" + ] + } + }, + "model.generated_6.shaped_stg_inventory_2": { + "database": null, + "schema": "main", + "name": "shaped_stg_inventory_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/shaped_stg_inventory_2.sql", + "original_file_path": "models/features/shaped_stg_inventory_2.sql", + "unique_id": "model.generated_6.shaped_stg_inventory_2", + "fqn": [ + "generated_6", + "models", + "features", + "shaped_stg_inventory_2" + ], + "alias": "shaped_stg_inventory_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Schema-shaped copy of stg_inventory_2", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.shaped_stg_inventory_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_2" + ] + } + }, + "model.generated_6.spaced_stg_fulfillment_0": { + "database": null, + "schema": "main", + "name": "spaced_stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/spaced_stg_fulfillment_0.sql", + "original_file_path": "models/features/spaced_stg_fulfillment_0.sql", + "unique_id": "model.generated_6.spaced_stg_fulfillment_0", + "fqn": [ + "generated_6", + "models", + "features", + "spaced_stg_fulfillment_0" + ], + "alias": "spaced_stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "línea", + "東京" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "línea", + "東京" + ], + "description": "Copy of stg_fulfillment_0 with 東京 warehouse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.spaced_stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_0" + ] + } + }, + "model.generated_6.taxed_stg_inventory_0": { + "database": null, + "schema": "main", + "name": "taxed_stg_inventory_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/features/taxed_stg_inventory_0.sql", + "original_file_path": "models/features/taxed_stg_inventory_0.sql", + "unique_id": "model.generated_6.taxed_stg_inventory_0", + "fqn": [ + "generated_6", + "models", + "features", + "taxed_stg_inventory_0" + ], + "alias": "taxed_stg_inventory_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Taxed copy of stg_inventory_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.taxed_stg_inventory_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_0" + ] + } + }, + "model.generated_6.fulfillment_summary_0": { + "database": null, + "schema": "main", + "name": "fulfillment_summary_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "original_file_path": "models/fulfillment/marts/fulfillment_summary_0.sql", + "unique_id": "model.generated_6.fulfillment_summary_0", + "fqn": [ + "generated_6", + "models", + "fulfillment", + "marts", + "fulfillment_summary_0" + ], + "alias": "fulfillment_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "fulfillment", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.fulfillment_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.fulfillment_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "fulfillment", + "marts" + ], + "description": "Summary of fulfillment activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.fulfillment_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.fulfillment_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.fulfillment_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_fulfillment_0" + ] + } + }, + "model.generated_6.stg_fulfillment_0": { + "database": null, + "schema": "main", + "name": "stg_fulfillment_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_0.sql", + "unique_id": "model.generated_6.stg_fulfillment_0", + "fqn": [ + "generated_6", + "models", + "fulfillment", + "staging", + "stg_fulfillment_0" + ], + "alias": "stg_fulfillment_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_fulfillment_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.stg_fulfillment_1": { + "database": null, + "schema": "main", + "name": "stg_fulfillment_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_1.sql", + "unique_id": "model.generated_6.stg_fulfillment_1", + "fqn": [ + "generated_6", + "models", + "fulfillment", + "staging", + "stg_fulfillment_1" + ], + "alias": "stg_fulfillment_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 1 (東京 warehouse)", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_fulfillment_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.stg_fulfillment_2": { + "database": null, + "schema": "main", + "name": "stg_fulfillment_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/fulfillment/staging/stg_fulfillment_2.sql", + "original_file_path": "models/fulfillment/staging/stg_fulfillment_2.sql", + "unique_id": "model.generated_6.stg_fulfillment_2", + "fqn": [ + "generated_6", + "models", + "fulfillment", + "staging", + "stg_fulfillment_2" + ], + "alias": "stg_fulfillment_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged fulfillment events 2", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_fulfillment_2", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.inventory_summary_0": { + "database": null, + "schema": "main", + "name": "inventory_summary_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/inventory/marts/inventory_summary_0.sql", + "original_file_path": "models/inventory/marts/inventory_summary_0.sql", + "unique_id": "model.generated_6.inventory_summary_0", + "fqn": [ + "generated_6", + "models", + "inventory", + "marts", + "inventory_summary_0" + ], + "alias": "inventory_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "inventory", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.inventory_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.inventory_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "inventory", + "marts" + ], + "description": "Summary of inventory activity 0", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "naïve résumé" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.inventory_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_1" + ] + } + }, + "model.generated_6.inventory_summary_1": { + "database": null, + "schema": "main", + "name": "inventory_summary_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/inventory/marts/inventory_summary_1.sql", + "original_file_path": "models/inventory/marts/inventory_summary_1.sql", + "unique_id": "model.generated_6.inventory_summary_1", + "fqn": [ + "generated_6", + "models", + "inventory", + "marts", + "inventory_summary_1" + ], + "alias": "inventory_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "inventory", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.inventory_summary_1' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.inventory_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "inventory", + "marts" + ], + "description": "Summary of inventory activity 1", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_1' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "café ☕ counter" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.inventory_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.inventory_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_2" + ] + } + }, + "model.generated_6.stg_inventory_0": { + "database": null, + "schema": "main", + "name": "stg_inventory_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/inventory/staging/stg_inventory_0.sql", + "original_file_path": "models/inventory/staging/stg_inventory_0.sql", + "unique_id": "model.generated_6.stg_inventory_0", + "fqn": [ + "generated_6", + "models", + "inventory", + "staging", + "stg_inventory_0" + ], + "alias": "stg_inventory_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged inventory events 0 (Ελληνικά orders)", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_inventory_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.stg_inventory_1": { + "database": null, + "schema": "main", + "name": "stg_inventory_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/inventory/staging/stg_inventory_1.sql", + "original_file_path": "models/inventory/staging/stg_inventory_1.sql", + "unique_id": "model.generated_6.stg_inventory_1", + "fqn": [ + "generated_6", + "models", + "inventory", + "staging", + "stg_inventory_1" + ], + "alias": "stg_inventory_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged inventory events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_inventory_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.stg_inventory_2": { + "database": null, + "schema": "main", + "name": "stg_inventory_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/inventory/staging/stg_inventory_2.sql", + "original_file_path": "models/inventory/staging/stg_inventory_2.sql", + "unique_id": "model.generated_6.stg_inventory_2", + "fqn": [ + "generated_6", + "models", + "inventory", + "staging", + "stg_inventory_2" + ], + "alias": "stg_inventory_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged inventory events 2", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_inventory_2", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + }, + "model.generated_6.large_events": { + "database": null, + "schema": "main", + "name": "large_events", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/rendering/large_events.sql", + "original_file_path": "models/rendering/large_events.sql", + "unique_id": "model.generated_6.large_events", + "fqn": [ + "generated_6", + "models", + "rendering", + "large_events" + ], + "alias": "large_events", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Events above a threshold from a table function", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.large_events", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.table_fn__events_above" + ] + } + }, + "model.generated_6.stated_stg_inventory_2": { + "database": null, + "schema": "main", + "name": "stated_stg_inventory_2", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/rendering/stated_stg_inventory_2.sql", + "original_file_path": "models/rendering/stated_stg_inventory_2.sql", + "unique_id": "model.generated_6.stated_stg_inventory_2", + "fqn": [ + "generated_6", + "models", + "rendering", + "stated_stg_inventory_2" + ], + "alias": "stated_stg_inventory_2", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Enum-typed copy of stg_inventory_2", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "tier": { + "name": "tier", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stated_stg_inventory_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_inventory_2" + ] + } + }, + "model.generated_6.sales_summary_0": { + "database": null, + "schema": "main", + "name": "sales_summary_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/sales/marts/sales_summary_0.sql", + "original_file_path": "models/sales/marts/sales_summary_0.sql", + "unique_id": "model.generated_6.sales_summary_0", + "fqn": [ + "generated_6", + "models", + "sales", + "marts", + "sales_summary_0" + ], + "alias": "sales_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'main.sales_summary_0' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'main.sales_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of sales activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'main.sales_summary_0' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "東京 warehouse" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'main.sales_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.sales_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_sales_0" + ] + } + }, + "model.generated_6.sales_summary_1": { + "database": null, + "schema": "main", + "name": "sales_summary_1", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/sales/marts/sales_summary_1.sql", + "original_file_path": "models/sales/marts/sales_summary_1.sql", + "unique_id": "model.generated_6.sales_summary_1", + "fqn": [ + "generated_6", + "models", + "sales", + "marts", + "sales_summary_1" + ], + "alias": "sales_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of sales activity 1 (café ☕ counter)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.sales_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_6.stg_sales_0", + "model.generated_6.stg_inventory_1" + ] + } + }, + "model.generated_6.stg_sales_0": { + "database": null, + "schema": "main", + "name": "stg_sales_0", + "resource_type": "model", + "package_name": "generated_6", + "path": "models/sales/staging/stg_sales_0.sql", + "original_file_path": "models/sales/staging/stg_sales_0.sql", + "unique_id": "model.generated_6.stg_sales_0", + "fqn": [ + "generated_6", + "models", + "sales", + "staging", + "stg_sales_0" + ], + "alias": "stg_sales_0", + "config": { + "enabled": true, + "alias": null, + "schema": "main", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged sales events 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "main.stg_sales_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_6.raw_events_0" + ] + } + } + }, + "sources": { + "source.generated_6.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_6", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_6.raw_events_0", + "fqn": [ + "generated_6", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_6.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_6", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_6.adjust_0", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [ + "macro.generated_6.adjust_0_round" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.adjust_0_round": { + "name": "adjust_0_round", + "resource_type": "macro", + "package_name": "generated_6", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_6.adjust_0_round", + "macro_sql": "def adjust_0_round(expression: str) -> str:\n \"\"\"Round an amount to two places.\"\"\"\n return f\"ROUND({expression}, 2)\"\n\n\ndef adjust_0(expression: str) -> str:\n \"\"\"Double and round an amount.\"\"\"\n return adjust_0_round(f\"({expression} * 2)\")\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.round_amount": { + "name": "round_amount", + "resource_type": "macro", + "package_name": "generated_6", + "path": "macros/rounding.py", + "original_file_path": "macros/rounding.py", + "unique_id": "macro.generated_6.round_amount", + "macro_sql": "def round_amount(expression: str, places: int = 2) -> str:\n \"\"\"Round an amount.\"\"\"\n return f\"ROUND({expression}, {places})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.taxed": { + "name": "taxed", + "resource_type": "macro", + "package_name": "generated_6", + "path": "macros/tax.py", + "original_file_path": "macros/tax.py", + "unique_id": "macro.generated_6.taxed", + "macro_sql": "from macros.rounding import round_amount\n\n\ndef taxed(expression: str) -> str:\n \"\"\"Add tax to an amount, rounded.\"\"\"\n return round_amount(f\"{expression} * 1.2\")\n", + "depends_on": { + "macros": [ + "macro.generated_6.round_amount" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.analysis_region": { + "name": "analysis_region", + "resource_type": "macro", + "package_name": "generated_6", + "path": "models/analysis/_sqlbuild/_macros/regions.py", + "original_file_path": "models/analysis/_sqlbuild/_macros/regions.py", + "unique_id": "macro.generated_6.analysis_region", + "macro_sql": "def analysis_region() -> str:\n \"\"\"Return the region rows are assigned to.\"\"\"\n return \"'north'\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/analysis" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_6", + "path": "models/fulfillment/marts/_sqlbuild/_macros/adjust_1.py", + "original_file_path": "models/fulfillment/marts/_sqlbuild/_macros/adjust_1.py", + "unique_id": "macro.generated_6.adjust_1", + "macro_sql": "import os\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Tag an amount with the deployment region.\"\"\"\n region = os.environ.get(\"SQB_DIFFERENTIAL_REGION\", \"east\")\n return f\"({expression} + LENGTH('{region}'))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/fulfillment/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6.doubled": { + "name": "doubled", + "resource_type": "macro", + "package_name": "generated_6", + "path": "tests/unit/_macros/scaling.py", + "original_file_path": "tests/unit/_macros/scaling.py", + "unique_id": "macro.generated_6.doubled", + "macro_sql": "def doubled(expression: str) -> str:\n \"\"\"Double an amount.\"\"\"\n return f\"({expression} * 2)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_6__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_6__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_6__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_6.chain_1_stg_fulfillment_2": [ + "model.generated_6.contracted_stg_fulfillment_2" + ], + "model.generated_6.chain_2_stg_fulfillment_2": [ + "model.generated_6.chain_1_stg_fulfillment_2" + ], + "model.generated_6.chain_3_stg_fulfillment_2": [ + "model.generated_6.chain_2_stg_fulfillment_2" + ], + "model.generated_6.checked_stg_fulfillment_2": [ + "model.generated_6.stg_fulfillment_2" + ], + "model.generated_6.contracted_stg_fulfillment_2": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.cte_facts_stg_fulfillment_1": [ + "model.generated_6.stg_fulfillment_1" + ], + "model.generated_6.regional_stg_fulfillment_0": [ + "model.generated_6.stg_fulfillment_0" + ], + "model.generated_6.audited_stg_fulfillment_1": [ + "model.generated_6.stg_fulfillment_1" + ], + "model.generated_6.batched_rolling_window_stg_sales_0": [ + "model.generated_6.stg_sales_0" + ], + "model.generated_6.check_history_stg_inventory_1": [ + "model.generated_6.stg_inventory_1" + ], + "model.generated_6.copied_stg_fulfillment_2": [ + "model.generated_6.stg_fulfillment_2" + ], + "model.generated_6.flagged_stg_sales_0": [ + "model.generated_6.is_placed", + "model.generated_6.is_large", + "model.generated_6.stg_sales_0" + ], + "model.generated_6.hooked_stg_inventory_1": [ + "model.generated_6.stg_inventory_1" + ], + "model.generated_6.merge_stg_inventory_0": [ + "model.generated_6.stg_inventory_0" + ], + "model.generated_6.shaped_stg_inventory_2": [ + "model.generated_6.stg_inventory_2" + ], + "model.generated_6.spaced_stg_fulfillment_0": [ + "model.generated_6.stg_fulfillment_0" + ], + "model.generated_6.taxed_stg_inventory_0": [ + "model.generated_6.stg_inventory_0" + ], + "model.generated_6.fulfillment_summary_0": [ + "model.generated_6.stg_fulfillment_0" + ], + "model.generated_6.stg_fulfillment_0": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.stg_fulfillment_1": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.stg_fulfillment_2": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.inventory_summary_0": [ + "model.generated_6.stg_inventory_1" + ], + "model.generated_6.inventory_summary_1": [ + "model.generated_6.stg_inventory_2" + ], + "model.generated_6.stg_inventory_0": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.stg_inventory_1": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.stg_inventory_2": [ + "source.generated_6.raw_events_0" + ], + "model.generated_6.large_events": [ + "model.generated_6.table_fn__events_above" + ], + "model.generated_6.stated_stg_inventory_2": [ + "model.generated_6.stg_inventory_2" + ], + "model.generated_6.sales_summary_0": [ + "model.generated_6.stg_sales_0" + ], + "model.generated_6.sales_summary_1": [ + "model.generated_6.stg_sales_0", + "model.generated_6.stg_inventory_1" + ], + "model.generated_6.stg_sales_0": [ + "source.generated_6.raw_events_0" + ], + "source.generated_6.raw_events_0": [], + "model.generated_6.is_placed": [], + "model.generated_6.table_fn__events_above": [ + "model.generated_6.stg_sales_0" + ], + "model.generated_6.is_large": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/7.json b/tests/goldens/compiler/seed/7.json new file mode 100644 index 0000000000..3d5cdcde4e --- /dev/null +++ b/tests/goldens/compiler/seed/7.json @@ -0,0 +1,48 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown macro '@not_a_macro' in '/models/inventory/marts/inventory_summary_0.sql'. Available macros: adjust_0, adjust_1" + } + ] + }, + { + "label": "compile-store-warm", + "exit_code": 1, + "diagnostics": [ + { + "phase": "compile", + "severity": "error", + "code": "P001", + "message": "Unknown macro '@not_a_macro' in '/models/inventory/marts/inventory_summary_0.sql'. Available macros: adjust_0, adjust_1" + } + ] + }, + { + "label": "plan", + "exit_code": 1, + "diagnostics": [ + "Project discovery START", + "Project assembly START", + "Declaration parsing START", + "Declaration parsing OK ()", + "Python discovery START", + "Python discovery OK ()", + "Project assembly OK ()", + "Project discovery OK ()", + "Compiling project...", + "error[P001]: Unknown macro '@not_a_macro' in '/models/inventory/marts/inventory_summary_0.sql'. Available macros: adjust_0, adjust_1", + "", + "" + ] + } + ], + "compiled": {}, + "manifest": null +} diff --git a/tests/goldens/compiler/seed/8.json b/tests/goldens/compiler/seed/8.json new file mode 100644 index 0000000000..cbc5d67c7d --- /dev/null +++ b/tests/goldens/compiler/seed/8.json @@ -0,0 +1,2770 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/audited_stg_support_0/id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"audited_stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/checked_stg_support_0/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"checked_stg_support_0\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/checked_stg_support_0/expression_is_true.sql": [ + "SELECT *", + "FROM __ref(\"checked_stg_support_0\")", + "WHERE NOT (amount >= -1000)", + "" + ], + "audits/generic/checked_stg_support_0/relationships__id.sql": [ + "SELECT id", + "FROM __ref(\"checked_stg_support_0\")", + "WHERE id IS NOT NULL", + " AND id NOT IN (", + " SELECT id", + " FROM __ref(\"stg_support_0\")", + " WHERE id IS NOT NULL", + " )", + "" + ], + "audits/generic/configured_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"configured_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN ('1')", + "" + ], + "audits/generic/configured_stg_support_0/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'shipped')", + "" + ], + "audits/generic/configured_stg_support_0/configured_amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE amount < -40", + "" + ], + "audits/generic/configured_stg_support_0/configured_id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_stg_support_0/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __ref(\"configured_stg_support_0\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/labelled_stg_support_0/tidy_status__status.sql": [ + "SELECT *", + "FROM __ref(\"labelled_stg_support_0\")", + "WHERE status <> LOWER(TRIM(status))", + "" + ], + "audits/generic/shaped_stg_support_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"shaped_stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/stg_support_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_support_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/support_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"support_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/support_summary_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"support_summary_1\")", + "WHERE id IS NULL", + "" + ], + "audits/singular/labelled_channels_match.sql": [ + "SELECT l.id", + "FROM __ref(\"labelled_stg_support_0\") l", + "JOIN __ref(\"channel_labels\") c ON l.id = c.id", + "WHERE l.status = c.channel", + "" + ], + "functions/sql/configured_label.sql": [ + "CREATE OR REPLACE MACRO ci_checks.configured_label(raw_status) AS (", + "UPPER(raw_status)", + ")", + "" + ], + "functions/sql/tidy_status.sql": [ + "CREATE OR REPLACE MACRO ci_checks.tidy_status(raw_status) AS (", + "LOWER(TRIM(raw_status))", + ")", + "" + ], + "models/analysis/checked_stg_support_0.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/pivot_input_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR) AS status, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/pivoted_stg_support_0.sql": [ + "PIVOT __ref(\"pivot_input_stg_support_0\")", + "ON status", + "USING MAX(amount)", + "GROUP BY id", + "" + ], + "models/analysis/unanalysed_stg_support_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_0\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/features/append_stg_support_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/audited_stg_support_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/batched_rolling_window_stg_support_0.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_support_0\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/hooked_stg_support_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/product_labels.sql": [ + "SELECT id, label", + "FROM __source(\"loaded_products\")", + "" + ], + "models/features/shaped_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/taxed_stg_support_0.sql": [ + "SELECT id, ROUND(amount * 1.2, 2) AS taxed, ROUND(amount, 1) AS rounded", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/rendering/bounded_stg_support_0.sql": [ + "SELECT id, amount, created_at", + "FROM __ref(\"stg_support_0\")", + "WHERE created_at >= __cursor_start()", + " AND created_at < __cursor_end()", + "" + ], + "models/rendering/channel_labels.sql": [ + "SELECT id, channel", + "FROM __source(\"labelled_channels\")", + "" + ], + "models/rendering/configured_stg_support_0.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/rendering/labelled_stg_support_0.sql": [ + "SELECT id, LOWER(TRIM(status)) AS status,", + " __udf(\"tidy_status\")(status) AS tidied", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/rendering/latest_raw_events_1.sql": [ + "SELECT id, amount", + "FROM (SELECT id, amount FROM __source(\"raw_events_1\") ORDER BY id DESC LIMIT 2) AS latest", + "" + ], + "models/rendering/unioned_event_ids.sql": [ + "SELECT id", + "FROM (SELECT id FROM __ref(\"stg_support_0\") UNION ALL SELECT id FROM __ref(\"stg_support_0\")) AS unioned", + "" + ], + "models/support/marts/support_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount * (1 - 0.15)) AS adjust_0_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __ref(\"stg_support_0\") t", + "WHERE t.status <> 'placed'", + "" + ], + "models/support/marts/support_summary_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " (t.amount * (1 - 0.15)) AS adjust_0_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " 'naïve résumé' AS site_label", + "FROM __ref(\"stg_support_0\") t", + "" + ], + "models/support/marts/support_summary_2.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 0.15 AS threshold_1_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __ref(\"stg_support_0\") t", + "" + ], + "models/support/staging/stg_support_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source(\"raw_events_0\") t", + "WHERE t.status <> 'expédié'", + "" + ], + "tests/_chain_/labelled_stg_support_0__stg_support_0/test_labelled_stg_support_0.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(1 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-01 00:00:00' AS created_at UNION ALL SELECT 2 AS id, CAST(2 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-02 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source__raw_events_0 t", + "WHERE t.status <> 'expédié'),", + "__ref__labelled_stg_support_0 AS (SELECT id, LOWER(TRIM(status)) AS status,", + " ci_checks.tidy_status(status) AS tidied", + "FROM __ref__stg_support_0),", + "__actual__labelled_stg_support_0 AS (SELECT * FROM __ref__labelled_stg_support_0),", + "__expected__labelled_stg_support_0 AS (SELECT 1 AS id, LOWER(TRIM('placed')) AS status", + " UNION ALL", + " SELECT 2 AS id, 'placed' AS status)", + "SELECT 1 AS step_index, 'labelled_stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__labelled_stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__labelled_stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__labelled_stg_support_0 EXCEPT SELECT id, status FROM __expected__labelled_stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__labelled_stg_support_0 EXCEPT SELECT id, status FROM __actual__labelled_stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/macro doubles_amounts/doubles_amounts.sql": [ + "WITH input_values AS (SELECT 4 AS amount),", + "__actual__macro_doubles_amounts AS (SELECT (amount * 2) AS doubled", + " FROM input_values),", + "__expected__macro_doubles_amounts AS (SELECT 8 AS doubled)", + "SELECT 0 AS step_index, 'macro doubles_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_doubles_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_doubles_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_doubles_amounts EXCEPT SELECT * FROM __expected__macro_doubles_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_doubles_amounts EXCEPT SELECT * FROM __actual__macro_doubles_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/macro taxes_amounts/taxes_amounts.sql": [ + "WITH input_values AS (SELECT 10 AS amount),", + "__actual__macro_taxes_amounts AS (SELECT ROUND(amount * 1.2, 2) AS taxed", + " FROM input_values),", + "__expected__macro_taxes_amounts AS (SELECT 12.0 AS taxed)", + "SELECT 0 AS step_index, 'macro taxes_amounts' AS model_name, (SELECT COUNT(*) FROM __actual__macro_taxes_amounts) AS actual_count, (SELECT COUNT(*) FROM __expected__macro_taxes_amounts) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__macro_taxes_amounts EXCEPT SELECT * FROM __expected__macro_taxes_amounts) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__macro_taxes_amounts EXCEPT SELECT * FROM __actual__macro_taxes_amounts) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_support_0/test_stg_support_0.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source__raw_events_0 t", + "WHERE t.status <> 'expédié'),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_support_0 EXCEPT SELECT id, status FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_support_0 EXCEPT SELECT id, status FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__labelled.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(2.25 AS DOUBLE) AS amount,", + " 'café ☕ counter' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source__raw_events_0 t", + "WHERE t.status <> 'expédié'),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__placed.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(1.5 AS DOUBLE) AS amount,", + " 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount + 237 AS threshold_0_amount,", + " t.amount + 50 AS threshold_2_amount,", + " (t.amount + LENGTH('east')) AS adjust_1_amount,", + " (t.amount + 2 + 1) AS adjust_2_amount", + "FROM __source__raw_events_0 t", + "WHERE t.status <> 'expédié'),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_8.checked_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "checked_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/analysis/checked_stg_support_0.sql", + "original_file_path": "models/analysis/checked_stg_support_0.sql", + "unique_id": "model.generated_8.checked_stg_support_0", + "fqn": [ + "generated_8", + "models", + "analysis", + "checked_stg_support_0" + ], + "alias": "checked_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Metadata-checked copy of stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.checked_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.pivot_input_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivot_input_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/analysis/pivot_input_stg_support_0.sql", + "original_file_path": "models/analysis/pivot_input_stg_support_0.sql", + "unique_id": "model.generated_8.pivot_input_stg_support_0", + "fqn": [ + "generated_8", + "models", + "analysis", + "pivot_input_stg_support_0" + ], + "alias": "pivot_input_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted pivot input from stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivot_input_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.pivoted_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivoted_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/analysis/pivoted_stg_support_0.sql", + "original_file_path": "models/analysis/pivoted_stg_support_0.sql", + "unique_id": "model.generated_8.pivoted_stg_support_0", + "fqn": [ + "generated_8", + "models", + "analysis", + "pivoted_stg_support_0" + ], + "alias": "pivoted_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amounts of stg_support_0 pivoted by status", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivoted_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.pivot_input_stg_support_0" + ] + } + }, + "model.generated_8.unanalysed_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "unanalysed_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/analysis/unanalysed_stg_support_0.sql", + "original_file_path": "models/analysis/unanalysed_stg_support_0.sql", + "unique_id": "model.generated_8.unanalysed_stg_support_0", + "fqn": [ + "generated_8", + "models", + "analysis", + "unanalysed_stg_support_0" + ], + "alias": "unanalysed_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_support_0 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unanalysed_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.append_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "append_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/append_stg_support_0.sql", + "original_file_path": "models/features/append_stg_support_0.sql", + "unique_id": "model.generated_8.append_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "append_stg_support_0" + ], + "alias": "append_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "append", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental append copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.append_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.audited_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "audited_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/audited_stg_support_0.sql", + "original_file_path": "models/features/audited_stg_support_0.sql", + "unique_id": "model.generated_8.audited_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "audited_stg_support_0" + ], + "alias": "audited_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Factory-audited copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.audited_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.batched_rolling_window_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "batched_rolling_window_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/batched_rolling_window_stg_support_0.sql", + "original_file_path": "models/features/batched_rolling_window_stg_support_0.sql", + "unique_id": "model.generated_8.batched_rolling_window_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "batched_rolling_window_stg_support_0" + ], + "alias": "batched_rolling_window_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched rolling_window totals of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.batched_rolling_window_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.hooked_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "hooked_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/hooked_stg_support_0.sql", + "original_file_path": "models/features/hooked_stg_support_0.sql", + "unique_id": "model.generated_8.hooked_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "hooked_stg_support_0" + ], + "alias": "hooked_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Hooked copy of stg_support_0", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "python", + "name": "note_refresh", + "kwargs": { + "channel": "東京 warehouse" + }, + "relative_path": "models/features/_sqlbuild/_hooks/python/notify.py", + "definition_hash": "55440ff19f0c4f231ad57d453227a3c9d584b81234ee4b3338a39ccdf59814a8", + "version_hash": "03b4f786f8ab2736e5be2e4de5016bd16ea44d84beca000ec2a53a397e503eb6" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.hooked_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.product_labels": { + "database": null, + "schema": "ci_checks", + "name": "product_labels", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/product_labels.sql", + "original_file_path": "models/features/product_labels.sql", + "unique_id": "model.generated_8.product_labels", + "fqn": [ + "generated_8", + "models", + "features", + "product_labels" + ], + "alias": "product_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Product labels from the loader", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.product_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_8.loaded_products" + ] + } + }, + "model.generated_8.shaped_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "shaped_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/shaped_stg_support_0.sql", + "original_file_path": "models/features/shaped_stg_support_0.sql", + "unique_id": "model.generated_8.shaped_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "shaped_stg_support_0" + ], + "alias": "shaped_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Schema-shaped copy of stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.shaped_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.taxed_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "taxed_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/features/taxed_stg_support_0.sql", + "original_file_path": "models/features/taxed_stg_support_0.sql", + "unique_id": "model.generated_8.taxed_stg_support_0", + "fqn": [ + "generated_8", + "models", + "features", + "taxed_stg_support_0" + ], + "alias": "taxed_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Taxed copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.taxed_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.bounded_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "bounded_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/bounded_stg_support_0.sql", + "original_file_path": "models/rendering/bounded_stg_support_0.sql", + "unique_id": "model.generated_8.bounded_stg_support_0", + "fqn": [ + "generated_8", + "models", + "rendering", + "bounded_stg_support_0" + ], + "alias": "bounded_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Cursor-bounded copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.bounded_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.channel_labels": { + "database": null, + "schema": "ci_checks", + "name": "channel_labels", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/channel_labels.sql", + "original_file_path": "models/rendering/channel_labels.sql", + "unique_id": "model.generated_8.channel_labels", + "fqn": [ + "generated_8", + "models", + "rendering", + "channel_labels" + ], + "alias": "channel_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Normalised channel labels", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.channel_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_8.labelled_channels" + ] + } + }, + "model.generated_8.configured_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "configured_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/configured_stg_support_0.sql", + "original_file_path": "models/rendering/configured_stg_support_0.sql", + "unique_id": "model.generated_8.configured_stg_support_0", + "fqn": [ + "generated_8", + "models", + "rendering", + "configured_stg_support_0" + ], + "alias": "configured_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "release" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "release" + ], + "description": "Configured copy of stg_support_0 (réglé)", + "columns": { + "id": { + "name": "id", + "description": "Row key", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Montant réglé", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.configured_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.labelled_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "labelled_stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/labelled_stg_support_0.sql", + "original_file_path": "models/rendering/labelled_stg_support_0.sql", + "unique_id": "model.generated_8.labelled_stg_support_0", + "fqn": [ + "generated_8", + "models", + "rendering", + "labelled_stg_support_0" + ], + "alias": "labelled_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Labelled copy of stg_support_0", + "columns": { + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.labelled_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.tidy_status", + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.latest_raw_events_1": { + "database": null, + "schema": "ci_checks", + "name": "latest_raw_events_1", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/latest_raw_events_1.sql", + "original_file_path": "models/rendering/latest_raw_events_1.sql", + "unique_id": "model.generated_8.latest_raw_events_1", + "fqn": [ + "generated_8", + "models", + "rendering", + "latest_raw_events_1" + ], + "alias": "latest_raw_events_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Newest rows of raw_events_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.latest_raw_events_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_8.raw_events_1" + ] + } + }, + "model.generated_8.unioned_event_ids": { + "database": null, + "schema": "ci_checks", + "name": "unioned_event_ids", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/rendering/unioned_event_ids.sql", + "original_file_path": "models/rendering/unioned_event_ids.sql", + "unique_id": "model.generated_8.unioned_event_ids", + "fqn": [ + "generated_8", + "models", + "rendering", + "unioned_event_ids" + ], + "alias": "unioned_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids from two staged relations", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unioned_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.support_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/support/marts/support_summary_0.sql", + "original_file_path": "models/support/marts/support_summary_0.sql", + "unique_id": "model.generated_8.support_summary_0", + "fqn": [ + "generated_8", + "models", + "support", + "marts", + "support_summary_0" + ], + "alias": "support_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of support activity 0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'naïve résumé' AS refresh_label", + "name": "record_refresh", + "relative_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "naïve résumé" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.support_summary_1": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_1", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/support/marts/support_summary_1.sql", + "original_file_path": "models/support/marts/support_summary_1.sql", + "unique_id": "model.generated_8.support_summary_1", + "fqn": [ + "generated_8", + "models", + "support", + "marts", + "support_summary_1" + ], + "alias": "support_summary_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.support_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.support_summary_1' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of support activity 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_1' AS refreshed_relation, '東京 warehouse' AS refresh_label", + "name": "record_refresh", + "relative_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "東京 warehouse" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_1' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.support_summary_2": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_2", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/support/marts/support_summary_2.sql", + "original_file_path": "models/support/marts/support_summary_2.sql", + "unique_id": "model.generated_8.support_summary_2", + "fqn": [ + "generated_8", + "models", + "support", + "marts", + "support_summary_2" + ], + "alias": "support_summary_2", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.support_summary_2' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.support_summary_2' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of support activity 2", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_2' AS refreshed_relation, 'Zürich – depot' AS refresh_label", + "name": "record_refresh", + "relative_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Zürich – depot" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_2' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_2", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_8.stg_support_0" + ] + } + }, + "model.generated_8.stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_support_0", + "resource_type": "model", + "package_name": "generated_8", + "path": "models/support/staging/stg_support_0.sql", + "original_file_path": "models/support/staging/stg_support_0.sql", + "unique_id": "model.generated_8.stg_support_0", + "fqn": [ + "generated_8", + "models", + "support", + "staging", + "stg_support_0" + ], + "alias": "stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged support events 0 (東京 warehouse)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_8.raw_events_0" + ] + } + } + }, + "sources": { + "source.generated_8.configured_events": { + "database": null, + "schema": "", + "name": "configured_events", + "resource_type": "source", + "package_name": "generated_8", + "path": "sources/configured.yml", + "original_file_path": "sources/configured.yml", + "unique_id": "source.generated_8.configured_events", + "fqn": [ + "generated_8", + "configured_events" + ], + "source_name": "configured_events", + "source_description": "", + "loader": "", + "identifier": "configured_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Configured feed events", + "columns": { + "id": { + "name": "id", + "description": "Key id", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "owner": "orders team" + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_8.labelled_channels": { + "database": null, + "schema": "", + "name": "labelled_channels", + "resource_type": "source", + "package_name": "generated_8", + "path": "sources/labelled.yml", + "original_file_path": "sources/labelled.yml", + "unique_id": "source.generated_8.labelled_channels", + "fqn": [ + "generated_8", + "labelled_channels" + ], + "source_name": "labelled_channels", + "source_description": "", + "loader": "", + "identifier": "labelled_channels", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Channel labels normalised in the source expression.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "channel": { + "name": "channel", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_8.loaded_products": { + "database": null, + "schema": "ci_checks", + "name": "loaded_products", + "resource_type": "source", + "package_name": "generated_8", + "path": "sources/managed.yml", + "original_file_path": "sources/managed.yml", + "unique_id": "source.generated_8.loaded_products", + "fqn": [ + "generated_8", + "loaded_products" + ], + "source_name": "loaded_products", + "source_description": "", + "loader": "", + "identifier": "loaded_products", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Products loaded by a project loader.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "loaded_products", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_8.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_8", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_8.raw_events_0", + "fqn": [ + "generated_8", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_8.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_8", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_8.raw_events_1", + "fqn": [ + "generated_8", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_8.tidy_label": { + "name": "tidy_label", + "resource_type": "macro", + "package_name": "generated_8", + "path": "macros/labels.py", + "original_file_path": "macros/labels.py", + "unique_id": "macro.generated_8.tidy_label", + "macro_sql": "def tidy_label(expression: str) -> str:\n \"\"\"Trim and lower-case a label.\"\"\"\n return f\"LOWER(TRIM({expression}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.round_amount": { + "name": "round_amount", + "resource_type": "macro", + "package_name": "generated_8", + "path": "macros/rounding.py", + "original_file_path": "macros/rounding.py", + "unique_id": "macro.generated_8.round_amount", + "macro_sql": "def round_amount(expression: str, places: int = 2) -> str:\n \"\"\"Round an amount.\"\"\"\n return f\"ROUND({expression}, {places})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.taxed": { + "name": "taxed", + "resource_type": "macro", + "package_name": "generated_8", + "path": "macros/tax.py", + "original_file_path": "macros/tax.py", + "unique_id": "macro.generated_8.taxed", + "macro_sql": "from macros.rounding import round_amount\n\n\ndef taxed(expression: str) -> str:\n \"\"\"Add tax to an amount, rounded.\"\"\"\n return round_amount(f\"{expression} * 1.2\")\n", + "depends_on": { + "macros": [ + "macro.generated_8.round_amount" + ] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.latest_rows": { + "name": "latest_rows", + "resource_type": "macro", + "package_name": "generated_8", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_8.latest_rows", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.union_ids": { + "name": "union_ids", + "resource_type": "macro", + "package_name": "generated_8", + "path": "models/rendering/_sqlbuild/_macros/relations.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/relations.py", + "unique_id": "macro.generated_8.union_ids", + "macro_sql": "from sqlbuild.refs import SqlResourceRef\n\n\ndef union_ids(relations: list[SqlResourceRef]) -> str:\n \"\"\"Union the ids of several relations.\"\"\"\n selects = [f\"SELECT id FROM {relation}\" for relation in relations]\n return \" UNION ALL \".join(selects)\n\n\ndef latest_rows(relation: SqlResourceRef, limit: int = 2) -> str:\n \"\"\"Return the newest rows of one relation.\"\"\"\n return f\"(SELECT id, amount FROM {relation} ORDER BY id DESC LIMIT {limit})\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.adjust_1": { + "name": "adjust_1", + "resource_type": "macro", + "package_name": "generated_8", + "path": "models/support/_sqlbuild/macros/adjust_1.py", + "original_file_path": "models/support/_sqlbuild/macros/adjust_1.py", + "unique_id": "macro.generated_8.adjust_1", + "macro_sql": "import os\n\n\ndef adjust_1(expression: str) -> str:\n \"\"\"Tag an amount with the deployment region.\"\"\"\n region = os.environ.get(\"SQB_DIFFERENTIAL_REGION\", \"east\")\n return f\"({expression} + LENGTH('{region}'))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/support" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.adjust_2": { + "name": "adjust_2", + "resource_type": "macro", + "package_name": "generated_8", + "path": "models/support/_sqlbuild/macros/adjust_2.py", + "original_file_path": "models/support/_sqlbuild/macros/adjust_2.py", + "unique_id": "macro.generated_8.adjust_2", + "macro_sql": "def adjust_2(expression: str) -> str:\n \"\"\"Offset an amount.\"\"\"\n return f\"({expression} + 2 + 1)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "inherited", + "sqlbuild_scope_path": "models/support" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_8", + "path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "original_file_path": "models/support/marts/_sqlbuild/_macros/adjust_0.py", + "unique_id": "macro.generated_8.adjust_0", + "macro_sql": "def adjust_0(ctx, expression: str) -> str:\n \"\"\"Scale an amount by the configured discount.\"\"\"\n rate = ctx.vars[\"discount_rate\"]\n return f\"({expression} * (1 - {rate}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/support/marts" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.doubled": { + "name": "doubled", + "resource_type": "macro", + "package_name": "generated_8", + "path": "tests/unit/_macros/scaling.py", + "original_file_path": "tests/unit/_macros/scaling.py", + "unique_id": "macro.generated_8.doubled", + "macro_sql": "def doubled(expression: str) -> str:\n \"\"\"Double an amount.\"\"\"\n return f\"({expression} * 2)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8.event_rows": { + "name": "event_rows", + "resource_type": "macro", + "package_name": "generated_8", + "path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "original_file_path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "unique_id": "macro.generated_8.event_rows", + "macro_sql": "def event_rows(count: int = 2) -> str:\n \"\"\"Return fixture event rows.\"\"\"\n return \" UNION ALL \".join(\n f\"SELECT {index} AS id, CAST({index} AS DOUBLE) AS amount, \"\n f\"'placed' AS status, \"\n f\"TIMESTAMP '2026-01-0{index} 00:00:00' AS created_at\"\n for index in range(1, count + 1)\n )\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_8__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_8__sqlbuild_hooks", + "path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "original_file_path": "models/support/marts/_sqlbuild/_hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_8__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_8.checked_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.pivot_input_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.pivoted_stg_support_0": [ + "model.generated_8.pivot_input_stg_support_0" + ], + "model.generated_8.unanalysed_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.append_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.audited_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.batched_rolling_window_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.hooked_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.product_labels": [ + "source.generated_8.loaded_products" + ], + "model.generated_8.shaped_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.taxed_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.bounded_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.channel_labels": [ + "source.generated_8.labelled_channels" + ], + "model.generated_8.configured_stg_support_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.labelled_stg_support_0": [ + "model.generated_8.tidy_status", + "model.generated_8.stg_support_0" + ], + "model.generated_8.latest_raw_events_1": [ + "source.generated_8.raw_events_1" + ], + "model.generated_8.unioned_event_ids": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.support_summary_0": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.support_summary_1": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.support_summary_2": [ + "model.generated_8.stg_support_0" + ], + "model.generated_8.stg_support_0": [ + "source.generated_8.raw_events_0" + ], + "source.generated_8.configured_events": [], + "source.generated_8.labelled_channels": [], + "source.generated_8.loaded_products": [], + "source.generated_8.raw_events_0": [], + "source.generated_8.raw_events_1": [], + "model.generated_8.configured_label": [], + "model.generated_8.tidy_status": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed/9.json b/tests/goldens/compiler/seed/9.json new file mode 100644 index 0000000000..cf030399cf --- /dev/null +++ b/tests/goldens/compiler/seed/9.json @@ -0,0 +1,3210 @@ +{ + "commands": [ + { + "label": "compile", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "compile-store-warm", + "exit_code": 0, + "diagnostics": [] + }, + { + "label": "plan", + "exit_code": 0, + "diagnostics": [] + } + ], + "compiled": { + "audits/generic/billing_summary_0/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"billing_summary_0\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_events/accepted_values__id.sql": [ + "SELECT id", + "FROM __source(\"configured_events\")", + "WHERE id IS NOT NULL", + " AND id NOT IN ('1')", + "" + ], + "audits/generic/configured_stg_support_1/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"configured_stg_support_1\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'shipped')", + "" + ], + "audits/generic/configured_stg_support_1/configured_amount_floor.sql": [ + "SELECT *", + "FROM __ref(\"configured_stg_support_1\")", + "WHERE amount < -37", + "" + ], + "audits/generic/configured_stg_support_1/configured_id_present__id.sql": [ + "SELECT id", + "FROM __ref(\"configured_stg_support_1\")", + "WHERE id IS NULL", + "" + ], + "audits/generic/configured_stg_support_1/unique__id.sql": [ + "SELECT id, COUNT(*) AS duplicate_count", + "FROM __ref(\"configured_stg_support_1\")", + "WHERE id IS NOT NULL", + "GROUP BY id", + "HAVING COUNT(*) > 1", + "" + ], + "audits/generic/guarded_stg_billing_0/amount_at_least__amount.sql": [ + "SELECT *", + "FROM __ref(\"guarded_stg_billing_0\")", + "WHERE amount < 0", + "" + ], + "audits/generic/labelled_stg_support_1/tidy_status__status.sql": [ + "SELECT *", + "FROM __ref(\"labelled_stg_support_1\")", + "WHERE status <> LOWER(TRIM(status))", + "" + ], + "audits/generic/stated_stg_support_0/accepted_values__status.sql": [ + "SELECT status", + "FROM __ref(\"stated_stg_support_0\")", + "WHERE status IS NOT NULL", + " AND status NOT IN ('placed', 'expédié', '取消', 'returned ✓')", + "" + ], + "audits/generic/stg_support_1/not_null__id.sql": [ + "SELECT id", + "FROM __ref(\"stg_support_1\")", + "WHERE id IS NULL", + "" + ], + "audits/singular/labelled_channels_match.sql": [ + "SELECT l.id", + "FROM __ref(\"labelled_stg_support_1\") l", + "JOIN __ref(\"channel_labels\") c ON l.id = c.id", + "WHERE l.status = c.channel", + "" + ], + "functions/python/is_large.sql": [ + "REGISTER PYTHON FUNCTION is_large(DOUBLE) RETURNS BOOLEAN", + "" + ], + "functions/sql/configured_label.sql": [ + "CREATE OR REPLACE MACRO ci_checks.configured_label(raw_status) AS (", + "UPPER(raw_status)", + ")", + "" + ], + "functions/sql/is_placed.sql": [ + "CREATE OR REPLACE MACRO ci_checks.is_placed(event_status) AS (", + "event_status = 'placed'", + ")", + "" + ], + "functions/sql/tidy_status.sql": [ + "CREATE OR REPLACE MACRO ci_checks.tidy_status(raw_status) AS (", + "LOWER(TRIM(raw_status))", + ")", + "" + ], + "models/analysis/combined_stg_billing_0.sql": [ + "WITH recent AS (", + " SELECT id, created_at FROM __ref(\"stg_billing_0\") WHERE amount > 0", + "),", + "older AS (", + " SELECT id, created_at FROM __ref(\"stg_support_0\")", + ")", + "SELECT id, created_at FROM recent", + "UNION ALL", + "SELECT id, created_at FROM older", + "" + ], + "models/analysis/every_open_event.sql": [ + "SELECT *", + "FROM __source(\"open_events\")", + "" + ], + "models/analysis/every_raw_events_1.sql": [ + "SELECT *", + "FROM __source(\"raw_events_1\")", + "" + ], + "models/analysis/every_stg_billing_0.sql": [ + "SELECT *", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/analysis/passed_stg_billing_0.sql": [ + "WITH passthrough AS (", + " SELECT id, created_at FROM __ref(\"stg_billing_0\")", + ")", + "SELECT id, created_at", + "FROM passthrough", + "" + ], + "models/analysis/pivot_input_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, CAST(status AS VARCHAR) AS status, amount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/pivoted_stg_support_0.sql": [ + "PIVOT __ref(\"pivot_input_stg_support_0\")", + "ON status", + "USING MAX(amount)", + "GROUP BY id", + "" + ], + "models/analysis/quoted_stg_support_0.sql": [ + "SELECT \"ID\" AS \"OrderKey\", \"Amount\", \"Status\" AS \"Status\"", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/analysis/typed_stg_billing_0.sql": [ + "SELECT id, amount * 2 AS doubled_amount, CAST(status AS VARCHAR) AS status_text,", + " created_at, NULL AS missing_note", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/analysis/unanalysed_stg_support_1.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_support_1\")", + "WHERE id = ANY [1, 2]", + "" + ], + "models/billing/marts/billing_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount", + "FROM __ref(\"stg_billing_0\") t", + "WHERE t.status <> 'placed'", + "" + ], + "models/billing/staging/stg_billing_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount,", + " (t.amount + 0 + 1) AS adjust_0_amount,", + " 'Zürich – depot' AS site_label", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/features/append_stg_support_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/batched_rolling_window_stg_support_1.sql": [ + "SELECT CAST(created_at AS DATE) AS created_at, SUM(amount) AS amount", + "FROM __ref(\"stg_support_1\")", + "GROUP BY CAST(created_at AS DATE)", + "" + ], + "models/features/delete_insert_stg_billing_0.sql": [ + "SELECT id, amount, status, created_at", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/features/flagged_stg_billing_0.sql": [ + "SELECT id, __udf(\"is_placed\")(status) AS is_placed,", + " __udf(\"is_large\")(amount) AS is_large", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/features/guarded_stg_billing_0.sql": [ + "SELECT id, amount", + "FROM __ref(\"stg_billing_0\")", + "" + ], + "models/features/kept_stg_support_1.sql": [ + "SELECT id, status, amount * 0.5 AS weighted", + "FROM __ref(\"stg_support_1\")", + "WHERE status IN ('取消', 'placed')", + " AND amount * 1.0 IN (0.5, 1.25, 2500.75) OR id > 0", + "" + ], + "models/features/product_labels.sql": [ + "SELECT id, label", + "FROM __source(\"loaded_products\")", + "" + ], + "models/features/spaced_stg_support_0.sql": [ + "-- Généré pour café ☕ counter", + "SELECT", + "\tid,", + "\t'Zürich – depot' AS label, -- étiquette ✓", + "\tamount", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/features/timestamp_history_stg_support_1.sql": [ + "SELECT id, status, created_at", + "FROM __ref(\"stg_support_1\")", + "" + ], + "models/rendering/channel_labels.sql": [ + "SELECT id, channel", + "FROM __source(\"labelled_channels\")", + "" + ], + "models/rendering/configured_stg_support_1.sql": [ + "SELECT id, amount, status", + "FROM __ref(\"stg_support_1\")", + "" + ], + "models/rendering/labelled_stg_support_1.sql": [ + "SELECT id, LOWER(TRIM(status)) AS status,", + " __udf(\"tidy_status\")(status) AS tidied", + "FROM __ref(\"stg_support_1\")", + "" + ], + "models/rendering/legacy_event_ids.sql": [ + "SELECT id", + "FROM __ref(\"stg_support_0\") AS legacy", + "" + ], + "models/rendering/stated_stg_support_0.sql": [ + "SELECT CAST(id AS INTEGER) AS id, status,", + " CASE WHEN amount >= 2 THEN 'HIGH'", + " ELSE 'LOW' END AS tier", + "FROM __ref(\"stg_support_0\")", + "" + ], + "models/support/marts/support_summary_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " 'Zürich – depot' AS site_label", + "FROM __ref(\"stg_support_0\") t", + "" + ], + "models/support/staging/stg_support_0.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "models/support/staging/stg_support_1.sql": [ + "SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + 0 + 1) AS adjust_0_amount", + "FROM __source(\"raw_events_0\") t", + "" + ], + "tests/_chain_/labelled_stg_support_1__stg_support_1/test_labelled_stg_support_1.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(1 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-01 00:00:00' AS created_at UNION ALL SELECT 2 AS id, CAST(2 AS DOUBLE) AS amount, 'placed' AS status, TIMESTAMP '2026-01-02 00:00:00' AS created_at),", + "__ref__stg_support_1 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " (t.amount + 0 + 1) AS adjust_0_amount", + "FROM __source__raw_events_0 t),", + "__ref__labelled_stg_support_1 AS (SELECT id, LOWER(TRIM(status)) AS status,", + " ci_checks.tidy_status(status) AS tidied", + "FROM __ref__stg_support_1),", + "__actual__labelled_stg_support_1 AS (SELECT * FROM __ref__labelled_stg_support_1),", + "__expected__labelled_stg_support_1 AS (SELECT 1 AS id, LOWER(TRIM('placed')) AS status", + " UNION ALL", + " SELECT 2 AS id, 'placed' AS status)", + "SELECT 1 AS step_index, 'labelled_stg_support_1' AS model_name, (SELECT COUNT(*) FROM __actual__labelled_stg_support_1) AS actual_count, (SELECT COUNT(*) FROM __expected__labelled_stg_support_1) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__labelled_stg_support_1 EXCEPT SELECT id, status FROM __expected__labelled_stg_support_1) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__labelled_stg_support_1 EXCEPT SELECT id, status FROM __actual__labelled_stg_support_1) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/stg_support_0/test_stg_support_0.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(10 AS DOUBLE) AS amount, 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id, 'placed' AS status)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __actual__stg_support_0 EXCEPT SELECT id, status FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id, status FROM __expected__stg_support_0 EXCEPT SELECT id, status FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__labelled.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(2.25 AS DOUBLE) AS amount,", + " 'Zürich – depot' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/tests/unit/test_stg_support_0_cases/block_1__placed.sql": [ + "WITH __source__raw_events_0 AS (SELECT 1 AS id, CAST(1.5 AS DOUBLE) AS amount,", + " 'placed' AS status,", + " TIMESTAMP '2026-01-01 00:00:00' AS created_at),", + "__ref__stg_support_0 AS (SELECT", + " t.id,", + " t.amount,", + " t.status,", + " t.created_at,", + " t.amount * 2.4700 AS threshold_0_amount", + "FROM __source__raw_events_0 t),", + "__actual__stg_support_0 AS (SELECT * FROM __ref__stg_support_0),", + "__expected__stg_support_0 AS (SELECT 1 AS id)", + "SELECT 0 AS step_index, 'stg_support_0' AS model_name, (SELECT COUNT(*) FROM __actual__stg_support_0) AS actual_count, (SELECT COUNT(*) FROM __expected__stg_support_0) AS expected_count, (SELECT COUNT(*) FROM (SELECT id FROM __actual__stg_support_0 EXCEPT SELECT id FROM __expected__stg_support_0) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT id FROM __expected__stg_support_0 EXCEPT SELECT id FROM __actual__stg_support_0) AS __sqlbuild_missing) AS missing_count", + "" + ], + "tests/udf detects_placed_events/detects_placed_events.sql": [ + "WITH input_values AS (SELECT 'placed' AS event_status),", + "__actual__udf_detects_placed_events AS (SELECT event_status, ci_checks.is_placed(event_status) AS is_placed", + " FROM input_values),", + "__expected__udf_detects_placed_events AS (SELECT 'placed' AS event_status, TRUE AS is_placed)", + "SELECT 0 AS step_index, 'udf detects_placed_events' AS model_name, (SELECT COUNT(*) FROM __actual__udf_detects_placed_events) AS actual_count, (SELECT COUNT(*) FROM __expected__udf_detects_placed_events) AS expected_count, (SELECT COUNT(*) FROM (SELECT * FROM __actual__udf_detects_placed_events EXCEPT SELECT * FROM __expected__udf_detects_placed_events) AS __sqlbuild_mismatch) AS unexpected_count, (SELECT COUNT(*) FROM (SELECT * FROM __expected__udf_detects_placed_events EXCEPT SELECT * FROM __actual__udf_detects_placed_events) AS __sqlbuild_missing) AS missing_count", + "" + ] + }, + "manifest": { + "nodes": { + "model.generated_9.combined_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "combined_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/combined_stg_billing_0.sql", + "original_file_path": "models/analysis/combined_stg_billing_0.sql", + "unique_id": "model.generated_9.combined_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "combined_stg_billing_0" + ], + "alias": "combined_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Recent and older rows of stg_billing_0 and stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.combined_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0", + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.every_open_event": { + "database": null, + "schema": "ci_checks", + "name": "every_open_event", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/every_open_event.sql", + "original_file_path": "models/analysis/every_open_event.sql", + "unique_id": "model.generated_9.every_open_event", + "fqn": [ + "generated_9", + "models", + "analysis", + "every_open_event" + ], + "alias": "every_open_event", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of an open source", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_open_event", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.open_events" + ] + } + }, + "model.generated_9.every_raw_events_1": { + "database": null, + "schema": "ci_checks", + "name": "every_raw_events_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/every_raw_events_1.sql", + "original_file_path": "models/analysis/every_raw_events_1.sql", + "unique_id": "model.generated_9.every_raw_events_1", + "fqn": [ + "generated_9", + "models", + "analysis", + "every_raw_events_1" + ], + "alias": "every_raw_events_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of raw_events_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_raw_events_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.raw_events_1" + ] + } + }, + "model.generated_9.every_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "every_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/every_stg_billing_0.sql", + "original_file_path": "models/analysis/every_stg_billing_0.sql", + "unique_id": "model.generated_9.every_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "every_stg_billing_0" + ], + "alias": "every_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Every column of stg_billing_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.every_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.passed_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "passed_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/passed_stg_billing_0.sql", + "original_file_path": "models/analysis/passed_stg_billing_0.sql", + "unique_id": "model.generated_9.passed_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "passed_stg_billing_0" + ], + "alias": "passed_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Columns of stg_billing_0 passed through a CTE", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.passed_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.pivot_input_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivot_input_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/pivot_input_stg_support_0.sql", + "original_file_path": "models/analysis/pivot_input_stg_support_0.sql", + "unique_id": "model.generated_9.pivot_input_stg_support_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "pivot_input_stg_support_0" + ], + "alias": "pivot_input_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Contracted pivot input from stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivot_input_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.pivoted_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "pivoted_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/pivoted_stg_support_0.sql", + "original_file_path": "models/analysis/pivoted_stg_support_0.sql", + "unique_id": "model.generated_9.pivoted_stg_support_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "pivoted_stg_support_0" + ], + "alias": "pivoted_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Amounts of stg_support_0 pivoted by status", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "dynamic_columns": [ + { + "name": "status_amounts", + "pivot_column": "status", + "value_column": "amount", + "aggregate": "MAX", + "type": "DOUBLE", + "name_pattern": null + } + ] + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.pivoted_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.pivot_input_stg_support_0" + ] + } + }, + "model.generated_9.quoted_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "quoted_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/quoted_stg_support_0.sql", + "original_file_path": "models/analysis/quoted_stg_support_0.sql", + "unique_id": "model.generated_9.quoted_stg_support_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "quoted_stg_support_0" + ], + "alias": "quoted_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Quoted identifiers over stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.quoted_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.typed_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "typed_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/typed_stg_billing_0.sql", + "original_file_path": "models/analysis/typed_stg_billing_0.sql", + "unique_id": "model.generated_9.typed_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "analysis", + "typed_stg_billing_0" + ], + "alias": "typed_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Typed and untyped outputs of stg_billing_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.typed_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.unanalysed_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "unanalysed_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/analysis/unanalysed_stg_support_1.sql", + "original_file_path": "models/analysis/unanalysed_stg_support_1.sql", + "unique_id": "model.generated_9.unanalysed_stg_support_1", + "fqn": [ + "generated_9", + "models", + "analysis", + "unanalysed_stg_support_1" + ], + "alias": "unanalysed_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Copy of stg_support_1 that SQL analysis cannot parse", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.unanalysed_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.billing_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "billing_summary_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/billing/marts/billing_summary_0.sql", + "original_file_path": "models/billing/marts/billing_summary_0.sql", + "unique_id": "model.generated_9.billing_summary_0", + "fqn": [ + "generated_9", + "models", + "billing", + "marts", + "billing_summary_0" + ], + "alias": "billing_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.billing_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.billing_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Summary of billing activity 0 (Zürich – depot)", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.billing_summary_0' AS refreshed_relation, 'Ελληνικά orders' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "Ελληνικά orders" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.billing_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.billing_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/billing/staging/stg_billing_0.sql", + "original_file_path": "models/billing/staging/stg_billing_0.sql", + "unique_id": "model.generated_9.stg_billing_0", + "fqn": [ + "generated_9", + "models", + "billing", + "staging", + "stg_billing_0" + ], + "alias": "stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged billing events 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.raw_events_0" + ] + } + }, + "model.generated_9.append_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "append_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/append_stg_support_0.sql", + "original_file_path": "models/features/append_stg_support_0.sql", + "unique_id": "model.generated_9.append_stg_support_0", + "fqn": [ + "generated_9", + "models", + "features", + "append_stg_support_0" + ], + "alias": "append_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "append", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental append copy of stg_support_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.append_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.batched_rolling_window_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "batched_rolling_window_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/batched_rolling_window_stg_support_1.sql", + "original_file_path": "models/features/batched_rolling_window_stg_support_1.sql", + "unique_id": "model.generated_9.batched_rolling_window_stg_support_1", + "fqn": [ + "generated_9", + "models", + "features", + "batched_rolling_window_stg_support_1" + ], + "alias": "batched_rolling_window_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Microbatched rolling_window totals of stg_support_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.batched_rolling_window_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.delete_insert_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "delete_insert_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/delete_insert_stg_billing_0.sql", + "original_file_path": "models/features/delete_insert_stg_billing_0.sql", + "unique_id": "model.generated_9.delete_insert_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "features", + "delete_insert_stg_billing_0" + ], + "alias": "delete_insert_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "incremental", + "incremental_strategy": "delete_insert", + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Incremental delete_insert copy of stg_billing_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.delete_insert_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.flagged_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "flagged_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/flagged_stg_billing_0.sql", + "original_file_path": "models/features/flagged_stg_billing_0.sql", + "unique_id": "model.generated_9.flagged_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "features", + "flagged_stg_billing_0" + ], + "alias": "flagged_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Function-flagged copy of stg_billing_0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.flagged_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.is_placed", + "model.generated_9.is_large", + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.guarded_stg_billing_0": { + "database": null, + "schema": "ci_checks", + "name": "guarded_stg_billing_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/guarded_stg_billing_0.sql", + "original_file_path": "models/features/guarded_stg_billing_0.sql", + "unique_id": "model.generated_9.guarded_stg_billing_0", + "fqn": [ + "generated_9", + "models", + "features", + "guarded_stg_billing_0" + ], + "alias": "guarded_stg_billing_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Generic-audited copy of stg_billing_0", + "columns": { + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.guarded_stg_billing_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_billing_0" + ] + } + }, + "model.generated_9.kept_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "kept_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/kept_stg_support_1.sql", + "original_file_path": "models/features/kept_stg_support_1.sql", + "unique_id": "model.generated_9.kept_stg_support_1", + "fqn": [ + "generated_9", + "models", + "features", + "kept_stg_support_1" + ], + "alias": "kept_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Statuses kept from stg_support_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.kept_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.product_labels": { + "database": null, + "schema": "ci_checks", + "name": "product_labels", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/product_labels.sql", + "original_file_path": "models/features/product_labels.sql", + "unique_id": "model.generated_9.product_labels", + "fqn": [ + "generated_9", + "models", + "features", + "product_labels" + ], + "alias": "product_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Product labels from the loader", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.product_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.loaded_products" + ] + } + }, + "model.generated_9.spaced_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "spaced_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/spaced_stg_support_0.sql", + "original_file_path": "models/features/spaced_stg_support_0.sql", + "unique_id": "model.generated_9.spaced_stg_support_0", + "fqn": [ + "generated_9", + "models", + "features", + "spaced_stg_support_0" + ], + "alias": "spaced_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "línea", + "東京" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "línea", + "東京" + ], + "description": "Copy of stg_support_0 with café ☕ counter", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.spaced_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.timestamp_history_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "timestamp_history_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/features/timestamp_history_stg_support_1.sql", + "original_file_path": "models/features/timestamp_history_stg_support_1.sql", + "unique_id": "model.generated_9.timestamp_history_stg_support_1", + "fqn": [ + "generated_9", + "models", + "features", + "timestamp_history_stg_support_1" + ], + "alias": "timestamp_history_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "snapshot", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": [ + "id" + ], + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Timestamp history of stg_support_1", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.timestamp_history_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.channel_labels": { + "database": null, + "schema": "ci_checks", + "name": "channel_labels", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/rendering/channel_labels.sql", + "original_file_path": "models/rendering/channel_labels.sql", + "unique_id": "model.generated_9.channel_labels", + "fqn": [ + "generated_9", + "models", + "rendering", + "channel_labels" + ], + "alias": "channel_labels", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Normalised channel labels", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.channel_labels", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.labelled_channels" + ] + } + }, + "model.generated_9.configured_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "configured_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/rendering/configured_stg_support_1.sql", + "original_file_path": "models/rendering/configured_stg_support_1.sql", + "unique_id": "model.generated_9.configured_stg_support_1", + "fqn": [ + "generated_9", + "models", + "rendering", + "configured_stg_support_1" + ], + "alias": "configured_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "release" + ], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "release" + ], + "description": "Configured copy of stg_support_1 (réglé)", + "columns": { + "id": { + "name": "id", + "description": "Row key", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "Montant réglé", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.configured_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.labelled_stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "labelled_stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/rendering/labelled_stg_support_1.sql", + "original_file_path": "models/rendering/labelled_stg_support_1.sql", + "unique_id": "model.generated_9.labelled_stg_support_1", + "fqn": [ + "generated_9", + "models", + "rendering", + "labelled_stg_support_1" + ], + "alias": "labelled_stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Labelled copy of stg_support_1", + "columns": { + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.labelled_stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.tidy_status", + "model.generated_9.stg_support_1" + ] + } + }, + "model.generated_9.legacy_event_ids": { + "database": null, + "schema": "ci_checks", + "name": "legacy_event_ids", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/rendering/legacy_event_ids.sql", + "original_file_path": "models/rendering/legacy_event_ids.sql", + "unique_id": "model.generated_9.legacy_event_ids", + "fqn": [ + "generated_9", + "models", + "rendering", + "legacy_event_ids" + ], + "alias": "legacy_event_ids", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Ids read through a macro-generated reference", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.legacy_event_ids", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.stated_stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "stated_stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/rendering/stated_stg_support_0.sql", + "original_file_path": "models/rendering/stated_stg_support_0.sql", + "unique_id": "model.generated_9.stated_stg_support_0", + "fqn": [ + "generated_9", + "models", + "rendering", + "stated_stg_support_0" + ], + "alias": "stated_stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [], + "meta": {}, + "group": null, + "materialized": "table", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [], + "description": "Enum-typed copy of stg_support_0", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "tier": { + "name": "tier", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stated_stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.support_summary_0": { + "database": null, + "schema": "ci_checks", + "name": "support_summary_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/support/marts/support_summary_0.sql", + "original_file_path": "models/support/marts/support_summary_0.sql", + "unique_id": "model.generated_9.support_summary_0", + "fqn": [ + "generated_9", + "models", + "support", + "marts", + "support_summary_0" + ], + "alias": "support_summary_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "support", + "marts" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [ + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "transaction": true, + "index": 0 + }, + { + "sql": "SELECT 'ci_checks.support_summary_0' AS refreshed", + "transaction": true, + "index": 1 + } + ], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "support", + "marts" + ], + "description": "Summary of support activity 0", + "columns": {}, + "meta": { + "sqlbuild": { + "lifecycle_hooks": { + "post_hooks": [ + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed_relation, 'café ☕ counter' AS refresh_label", + "name": "record_refresh", + "relative_path": "hooks/sql/record_refresh.sql", + "definition_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "kwargs": { + "relation": "@@CTX:destination.qualified", + "label": "café ☕ counter" + }, + "description": "Record a refresh for one relation" + }, + { + "type": "sql", + "statement": "SELECT 'ci_checks.support_summary_0' AS refreshed" + } + ] + } + } + }, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.support_summary_0", + "depends_on": { + "macros": [], + "nodes": [ + "model.generated_9.stg_support_0" + ] + } + }, + "model.generated_9.stg_support_0": { + "database": null, + "schema": "ci_checks", + "name": "stg_support_0", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/support/staging/stg_support_0.sql", + "original_file_path": "models/support/staging/stg_support_0.sql", + "unique_id": "model.generated_9.stg_support_0", + "fqn": [ + "generated_9", + "models", + "support", + "staging", + "stg_support_0" + ], + "alias": "stg_support_0", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged support events 0", + "columns": {}, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_support_0", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.raw_events_0" + ] + } + }, + "model.generated_9.stg_support_1": { + "database": null, + "schema": "ci_checks", + "name": "stg_support_1", + "resource_type": "model", + "package_name": "generated_9", + "path": "models/support/staging/stg_support_1.sql", + "original_file_path": "models/support/staging/stg_support_1.sql", + "unique_id": "model.generated_9.stg_support_1", + "fqn": [ + "generated_9", + "models", + "support", + "staging", + "stg_support_1" + ], + "alias": "stg_support_1", + "config": { + "enabled": true, + "alias": null, + "schema": "ci_checks", + "database": null, + "tags": [ + "staging" + ], + "meta": {}, + "group": null, + "materialized": "view", + "incremental_strategy": null, + "merge_exclude_columns": null, + "persist_docs": {}, + "post-hook": [], + "pre-hook": [], + "quoting": {}, + "column_types": {}, + "full_refresh": null, + "unique_key": null, + "on_schema_change": "ignore", + "on_configuration_change": "apply", + "grants": {}, + "packages": [], + "docs": { + "show": true, + "node_color": null + }, + "contract": { + "enforced": false, + "alias_types": true + } + }, + "tags": [ + "staging" + ], + "description": "Staged support events 1", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": null, + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "group": null, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "build_path": null, + "unrendered_config": {}, + "config_call_dict": {}, + "unrendered_config_call_dict": {}, + "relation_name": "ci_checks.stg_support_1", + "depends_on": { + "macros": [], + "nodes": [ + "source.generated_9.raw_events_0" + ] + } + } + }, + "sources": { + "source.generated_9.configured_events": { + "database": null, + "schema": "", + "name": "configured_events", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/configured.yml", + "original_file_path": "sources/configured.yml", + "unique_id": "source.generated_9.configured_events", + "fqn": [ + "generated_9", + "configured_events" + ], + "source_name": "configured_events", + "source_description": "", + "loader": "", + "identifier": "configured_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Configured feed events", + "columns": { + "id": { + "name": "id", + "description": "Key id", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "owner": "orders team" + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_9.labelled_channels": { + "database": null, + "schema": "", + "name": "labelled_channels", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/labelled.yml", + "original_file_path": "sources/labelled.yml", + "unique_id": "source.generated_9.labelled_channels", + "fqn": [ + "generated_9", + "labelled_channels" + ], + "source_name": "labelled_channels", + "source_description": "", + "loader": "", + "identifier": "labelled_channels", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Channel labels normalised in the source expression.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "channel": { + "name": "channel", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_9.loaded_products": { + "database": null, + "schema": "ci_checks", + "name": "loaded_products", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/managed.yml", + "original_file_path": "sources/managed.yml", + "unique_id": "source.generated_9.loaded_products", + "fqn": [ + "generated_9", + "loaded_products" + ], + "source_name": "loaded_products", + "source_description": "", + "loader": "", + "identifier": "loaded_products", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Products loaded by a project loader.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "label": { + "name": "label", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": { + "sqlbuild": { + "loader": "loaded_products", + "auto_load": false, + "write_strategy": "table" + } + }, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_9.open_events": { + "database": null, + "schema": "", + "name": "open_events", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/open.yml", + "original_file_path": "sources/open.yml", + "unique_id": "source.generated_9.open_events", + "fqn": [ + "generated_9", + "open_events" + ], + "source_name": "open_events", + "source_description": "", + "loader": "", + "identifier": "open_events", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Events whose columns are only known to the warehouse.", + "columns": {}, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_9.raw_events_0": { + "database": null, + "schema": "", + "name": "raw_events_0", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_9.raw_events_0", + "fqn": [ + "generated_9", + "raw_events_0" + ], + "source_name": "raw_events_0", + "source_description": "", + "loader": "", + "identifier": "raw_events_0", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 0.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + }, + "source.generated_9.raw_events_1": { + "database": null, + "schema": "", + "name": "raw_events_1", + "resource_type": "source", + "package_name": "generated_9", + "path": "sources/raw.yml", + "original_file_path": "sources/raw.yml", + "unique_id": "source.generated_9.raw_events_1", + "fqn": [ + "generated_9", + "raw_events_1" + ], + "source_name": "raw_events_1", + "source_description": "", + "loader": "", + "identifier": "raw_events_1", + "quoting": {}, + "loaded_at_field": null, + "freshness": null, + "external": null, + "description": "Generated event feed 1.", + "columns": { + "id": { + "name": "id", + "description": "", + "meta": {}, + "data_type": "INTEGER", + "constraints": [], + "quote": null, + "tags": [] + }, + "amount": { + "name": "amount", + "description": "", + "meta": {}, + "data_type": "DOUBLE", + "constraints": [], + "quote": null, + "tags": [] + }, + "status": { + "name": "status", + "description": "", + "meta": {}, + "data_type": "VARCHAR", + "constraints": [], + "quote": null, + "tags": [] + }, + "created_at": { + "name": "created_at", + "description": "", + "meta": {}, + "data_type": "TIMESTAMP", + "constraints": [], + "quote": null, + "tags": [] + } + }, + "meta": {}, + "source_meta": {}, + "tags": [], + "config": {}, + "patch_path": null, + "unrendered_config": {}, + "relation_name": null + } + }, + "macros": { + "macro.generated_9.adjust_0": { + "name": "adjust_0", + "resource_type": "macro", + "package_name": "generated_9", + "path": "macros/adjust_0.py", + "original_file_path": "macros/adjust_0.py", + "unique_id": "macro.generated_9.adjust_0", + "macro_sql": "def adjust_0(expression: str) -> str:\n \"\"\"Offset an amount.\"\"\"\n return f\"({expression} + 0 + 1)\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_9.tidy_label": { + "name": "tidy_label", + "resource_type": "macro", + "package_name": "generated_9", + "path": "macros/labels.py", + "original_file_path": "macros/labels.py", + "unique_id": "macro.generated_9.tidy_label", + "macro_sql": "def tidy_label(expression: str) -> str:\n \"\"\"Trim and lower-case a label.\"\"\"\n return f\"LOWER(TRIM({expression}))\"\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "global", + "sqlbuild_scope_path": null + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_9.legacy_events": { + "name": "legacy_events", + "resource_type": "macro", + "package_name": "generated_9", + "path": "models/rendering/_sqlbuild/_macros/legacy.py", + "original_file_path": "models/rendering/_sqlbuild/_macros/legacy.py", + "unique_id": "macro.generated_9.legacy_events", + "macro_sql": "def legacy_events() -> str:\n \"\"\"Return a staged relation the way a migrated project wrote it.\"\"\"\n return '__ref(\"stg_support_0\")'\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "models/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_9.event_rows": { + "name": "event_rows", + "resource_type": "macro", + "package_name": "generated_9", + "path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "original_file_path": "tests/unit/rendering/_sqlbuild/_macros/fixtures.py", + "unique_id": "macro.generated_9.event_rows", + "macro_sql": "def event_rows(count: int = 2) -> str:\n \"\"\"Return fixture event rows.\"\"\"\n return \" UNION ALL \".join(\n f\"SELECT {index} AS id, CAST({index} AS DOUBLE) AS amount, \"\n f\"'placed' AS status, \"\n f\"TIMESTAMP '2026-01-0{index} 00:00:00' AS created_at\"\n for index in range(1, count + 1)\n )\n", + "depends_on": { + "macros": [] + }, + "description": "", + "meta": { + "sqlbuild_visibility": "local", + "sqlbuild_scope_path": "tests/unit/rendering" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + }, + "macro.generated_9__sqlbuild_hooks.record_refresh": { + "name": "record_refresh", + "resource_type": "macro", + "package_name": "generated_9__sqlbuild_hooks", + "path": "hooks/sql/record_refresh.sql", + "original_file_path": "hooks/sql/record_refresh.sql", + "unique_id": "macro.generated_9__sqlbuild_hooks.record_refresh", + "macro_sql": "SELECT @'relation' AS refreshed_relation, @'label' AS refresh_label", + "depends_on": { + "macros": [] + }, + "description": "Record a refresh for one relation", + "meta": { + "sqlbuild_resource_type": "sql_hook", + "sqlbuild_hook_name": "record_refresh" + }, + "docs": { + "show": true, + "node_color": null + }, + "patch_path": null, + "arguments": [], + "supported_languages": null + } + }, + "exposures": {}, + "metrics": {}, + "groups": {}, + "selectors": {}, + "disabled": {}, + "parent_map": { + "model.generated_9.combined_stg_billing_0": [ + "model.generated_9.stg_billing_0", + "model.generated_9.stg_support_0" + ], + "model.generated_9.every_open_event": [ + "source.generated_9.open_events" + ], + "model.generated_9.every_raw_events_1": [ + "source.generated_9.raw_events_1" + ], + "model.generated_9.every_stg_billing_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.passed_stg_billing_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.pivot_input_stg_support_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.pivoted_stg_support_0": [ + "model.generated_9.pivot_input_stg_support_0" + ], + "model.generated_9.quoted_stg_support_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.typed_stg_billing_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.unanalysed_stg_support_1": [ + "model.generated_9.stg_support_1" + ], + "model.generated_9.billing_summary_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.stg_billing_0": [ + "source.generated_9.raw_events_0" + ], + "model.generated_9.append_stg_support_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.batched_rolling_window_stg_support_1": [ + "model.generated_9.stg_support_1" + ], + "model.generated_9.delete_insert_stg_billing_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.flagged_stg_billing_0": [ + "model.generated_9.is_placed", + "model.generated_9.is_large", + "model.generated_9.stg_billing_0" + ], + "model.generated_9.guarded_stg_billing_0": [ + "model.generated_9.stg_billing_0" + ], + "model.generated_9.kept_stg_support_1": [ + "model.generated_9.stg_support_1" + ], + "model.generated_9.product_labels": [ + "source.generated_9.loaded_products" + ], + "model.generated_9.spaced_stg_support_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.timestamp_history_stg_support_1": [ + "model.generated_9.stg_support_1" + ], + "model.generated_9.channel_labels": [ + "source.generated_9.labelled_channels" + ], + "model.generated_9.configured_stg_support_1": [ + "model.generated_9.stg_support_1" + ], + "model.generated_9.labelled_stg_support_1": [ + "model.generated_9.tidy_status", + "model.generated_9.stg_support_1" + ], + "model.generated_9.legacy_event_ids": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.stated_stg_support_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.support_summary_0": [ + "model.generated_9.stg_support_0" + ], + "model.generated_9.stg_support_0": [ + "source.generated_9.raw_events_0" + ], + "model.generated_9.stg_support_1": [ + "source.generated_9.raw_events_0" + ], + "source.generated_9.configured_events": [], + "source.generated_9.labelled_channels": [], + "source.generated_9.loaded_products": [], + "source.generated_9.open_events": [], + "source.generated_9.raw_events_0": [], + "source.generated_9.raw_events_1": [], + "model.generated_9.configured_label": [], + "model.generated_9.is_placed": [], + "model.generated_9.tidy_status": [], + "model.generated_9.is_large": [] + }, + "group_map": {}, + "docs": {}, + "saved_queries": {}, + "semantic_models": {}, + "unit_tests": {} + } +} diff --git a/tests/goldens/compiler/seed_range.toml b/tests/goldens/compiler/seed_range.toml new file mode 100644 index 0000000000..c0d6bdc52f --- /dev/null +++ b/tests/goldens/compiler/seed_range.toml @@ -0,0 +1,2 @@ +seed_start = 0 +seeds = 12 diff --git a/tests/integration/src/sqlbuild/adapter/type_system/_test_types.py b/tests/integration/src/sqlbuild/adapter/type_system/_test_types.py index 762e82405f..1d687c65c5 100644 --- a/tests/integration/src/sqlbuild/adapter/type_system/_test_types.py +++ b/tests/integration/src/sqlbuild/adapter/type_system/_test_types.py @@ -33,3 +33,15 @@ class DeepTypeTestCase: description: str type_sql: str expected_native: None + + +@dataclass(frozen=True) +class PublicNativeTypeTestCase: + """Types normalized through the public entry point under the preview engine.""" + + description: str + engine: str + dialect: str + type_strings: tuple[str, ...] + expected_native_calls: tuple[tuple[str, str], ...] + expected_answered: int diff --git a/tests/integration/src/sqlbuild/adapter/type_system/test_native_type_parity.py b/tests/integration/src/sqlbuild/adapter/type_system/test_native_type_parity.py index eb481b27a3..93ab4d3b7c 100644 --- a/tests/integration/src/sqlbuild/adapter/type_system/test_native_type_parity.py +++ b/tests/integration/src/sqlbuild/adapter/type_system/test_native_type_parity.py @@ -3,13 +3,22 @@ from __future__ import annotations import random +from collections.abc import Callable import pytest +import sqlbuild._native as native_module +from sqlbuild.adapter.contract.models import NormalizedType +from sqlbuild.adapter.type_system._helpers.type_normalization import ( + normalize_type as cached_normalize_type, +) from sqlbuild.adapter.type_system.main._native_normalize_type import normalize_native_type +from sqlbuild.adapter.type_system.main.normalize_type import normalize_type +from sqlbuild.compiler.frontier.constants import COMPILER_ENGINE_ENV_VAR from tests.integration.src.sqlbuild.adapter.type_system._test_types import ( DeepTypeTestCase, GeneratedTypeParityTestCase, + PublicNativeTypeTestCase, TypeParityTestCase, ) from tests.integration.src.sqlbuild.adapter.type_system.helpers import ( @@ -169,5 +178,51 @@ def test_given_type_past_the_wheel_depth_when_normalizing_natively_then_it_defer ) +@pytest.mark.parametrize( + "test_case", + [ + PublicNativeTypeTestCase( + description="the public entry point asks native first under the preview engine", + engine="native-preview", + dialect="snowflake", + type_strings=("NUMBER(38, 0)", "VARCHAR", "TIMESTAMP_NTZ(9)"), + expected_native_calls=( + ("NUMBER(38, 0)", "snowflake"), + ("VARCHAR", "snowflake"), + ("TIMESTAMP_NTZ(9)", "snowflake"), + ), + expected_answered=3, + ), + ], + ids=lambda case: case.description, +) +def test_given_preview_engine_when_normalizing_publicly_then_native_answers( + test_case: PublicNativeTypeTestCase, monkeypatch: pytest.MonkeyPatch +) -> None: + calls: list[tuple[str, str]] = [] + answers: list[object] = [] + native_normalize: Callable[[str, str], object] = native_module.normalize_type + + def spy(type_sql: str, dialect: str) -> object: + calls.append((type_sql, dialect)) + answers.append(native_normalize(type_sql, dialect)) + return answers[-1] + + monkeypatch.setenv(COMPILER_ENGINE_ENV_VAR, test_case.engine) + monkeypatch.setattr(native_module, "normalize_type", spy) + cached_normalize_type.cache_clear() + normalized: list[NormalizedType] = [ + normalize_type(type_sql=type_sql, dialect=test_case.dialect) + for type_sql in test_case.type_strings + ] + cached_normalize_type.cache_clear() + + assert ( + tuple(calls), + sum(answer is not None for answer in answers), + len(normalized), + ) == (test_case.expected_native_calls, test_case.expected_answered, len(test_case.type_strings)) + + if __name__ == "__main__": pytest.main([__file__, "-vv"]) diff --git a/tests/integration/src/sqlbuild/compiler/analysis_session/_test_helpers.py b/tests/integration/src/sqlbuild/compiler/analysis_session/_test_helpers.py new file mode 100644 index 0000000000..7622a8d2bf --- /dev/null +++ b/tests/integration/src/sqlbuild/compiler/analysis_session/_test_helpers.py @@ -0,0 +1,440 @@ +"""Seeded CTE queries and both CTE fact recoveries, compared function for function.""" + +from __future__ import annotations + +import random +from collections import Counter +from collections.abc import Callable +from dataclasses import dataclass +from typing import Any + +import sqlbuild._native as native_module +import sqlbuild.compiler.compile._helpers.analysis.compact as compact_analysis +from sqlbuild.adapter.contract.classes.base_adapter import BaseAdapter +from sqlbuild.adapter.contract.models import ExpressionInferenceProfile +from sqlbuild.adapter.type_system.main.conditional_result_nullability import ( + conditional_result_nullability, +) +from sqlbuild.adapter.type_system.main.first_arg_nullability import first_arg_nullability +from sqlbuild.adapters.bigquery.classes.bigquery_adapter import BigQueryAdapter +from sqlbuild.adapters.databricks.classes.databricks_adapter import DatabricksAdapter +from sqlbuild.adapters.duckdb.classes.duckdb_adapter import DuckDbAdapter +from sqlbuild.adapters.postgres.classes.postgres_adapter import PostgresAdapter +from sqlbuild.adapters.snowflake.classes.snowflake_adapter import SnowflakeAdapter +from sqlbuild.adapters.sqlserver.classes.sqlserver_adapter import SqlServerAdapter +from sqlbuild.compiler.analysis_session._helpers.session_rows import nullability_rule_rows +from sqlbuild.compiler.compile._helpers.analysis.cte_facts import ( + _polyglot_cte_passthrough_facts, + _polyglot_filtered_non_null_outputs, +) +from sqlbuild.compiler.compile.models import CteFactResolvers +from sqlbuild.compiler.lineage.types import InferredNullability +from sqlbuild.compiler.sql_analysis.main.import_polyglot import import_polyglot + +type Generate = Callable[[random.Random, list[str], int], str] +type CteFactView = ( + tuple[list[tuple[str, str]], list[tuple[str, str]], list[str], list[str]] | tuple[str, str] +) + + +@dataclass(frozen=True) +class CteFactQuery: + """One generated query and the enrichment facts both recoveries read.""" + + sql: str + profile: ExpressionInferenceProfile + recover: bool + null_filter: bool + + +@dataclass +class CteFactParity: + """Python's and native's recovered facts for every query native answered.""" + + queries: list[object] + python: list[object] + native: list[object] + counts: Counter[str] + + +_SCHEMAS: dict[str, dict[str, str]] = { + "orders": { + "order_id": "INTEGER", + "customer_id": "BIGINT", + "qty": "INT", + "price": "DECIMAL(10, 2)", + "big_price": "NUMERIC(12,2)", + "ratio": "DOUBLE", + "status": "VARCHAR", + "code": "VARCHAR(20)", + "note": "TEXT", + "flag": "BOOLEAN", + "placed_on": "DATE", + "placed_at": "TIMESTAMP", + "MixedCase": "INTEGER", + "mixedcase": "BIGINT", + "Price": "FLOAT", + }, + "customers": { + "customer_id": "BIGINT", + "order_id": "VARCHAR", + "region": "STRING", + "price": "DOUBLE", + "Region": "CHAR(2)", + "empty_type": "", + }, + "Events": {"event_id": "INT", "kind": "VARCHAR(10)"}, + "events": {"event_id": "BIGINT", "payload": "JSON"}, +} +_INPUT_NULLABILITY: dict[str, dict[str, InferredNullability]] = { + table: dict.fromkeys(columns, InferredNullability.UNKNOWN) + for table, columns in _SCHEMAS.items() +} +_INPUT_SHAPES: list[tuple[str, list[tuple[str, str]]]] = [ + (table, list(columns.items())) for table, columns in _SCHEMAS.items() +] +_NULL_FILTER_USE: dict[str, str] = {"context": "filter", "expressionSql": "x IS NOT NULL"} +_RESOLVERS: CteFactResolvers = CteFactResolvers( + expression_type=compact_analysis._polyglot_expression_type, + nullability=compact_analysis._infer_polyglot_nullability, + shallow_nullability=compact_analysis._infer_polyglot_shallow_nullability, + alias_nullability=compact_analysis._polyglot_alias_nullability_from_select, +) +_ADAPTERS: tuple[BaseAdapter, ...] = ( + DuckDbAdapter(), + SnowflakeAdapter(), + BigQueryAdapter(), + DatabricksAdapter(), + PostgresAdapter(), + SqlServerAdapter(), +) +# Rules apply by node kind. The wheel parses IF, IFF and IIF as `if_func`, whose arguments +# Python never collects, so adapters' IF/IFF rules stay unknown here; the profile keyed by +# node kinds with collected arguments reaches the conditional_result and first_arg rules. +PROFILES: tuple[ExpressionInferenceProfile, ...] = ( + *(adapter.expression_inference_profile() for adapter in _ADAPTERS), + ExpressionInferenceProfile( + sql_analysis_dialect="duckdb", + function_nullability_rules=DuckDbAdapter() + .expression_inference_profile() + .function_nullability_rules, + function_return_types={"LENGTH": "BIGINT", "UPPER": "VARCHAR(5)", "ABS": "DECIMAL(10,2)"}, + ), + ExpressionInferenceProfile( + sql_analysis_dialect="snowflake", + function_nullability_rules={ + "FUNCTION": conditional_result_nullability, + "IN": conditional_result_nullability, + "ARRAY_FUNC": first_arg_nullability, + "CONCAT": first_arg_nullability, + "UPPER": first_arg_nullability, + "LOWER": first_arg_nullability, + }, + function_return_types=SnowflakeAdapter() + .expression_inference_profile() + .function_return_types, + ), + ExpressionInferenceProfile(sql_analysis_dialect="generic"), + ExpressionInferenceProfile(sql_analysis_dialect=None), +) +_TYPES: tuple[str, ...] = ( + "INT", "INTEGER", "BIGINT", "SMALLINT", "TINYINT", "DECIMAL(10, 2)", "DECIMAL(12,2)", + "DECIMAL", "DECIMAL(9)", "NUMERIC(10, 2)", "NUMERIC", "NUMBER", "NUMBER(10, 2)", "VARCHAR", + "VARCHAR(10)", "TEXT", "STRING", "CHAR(3)", "DOUBLE", "FLOAT", "REAL", "FLOAT64", "INT64", + "BOOLEAN", "BOOL", "DATE", "TIMESTAMP", "TIMESTAMPTZ", "TIMESTAMP WITH TIME ZONE", + "TIMESTAMP_NTZ", "DATETIME", "JSON", "VARIANT", "BINARY", "HUGEINT", "BIGNUMERIC", + "NVARCHAR(5)", "DOUBLE PRECISION", "INTERVAL", "UUID", "ARRAY", "INT[]", + "STRUCT", "MAP(VARCHAR, INT)", +) # fmt: skip +_LITERALS: tuple[str, ...] = ("1", "'x'", "NULL", "1.5", "TRUE", "DATE '2020-01-01'") +_MAX_DEPTH: int = 3 +_ALIASES: tuple[str, ...] = ("b", "c", "o2", "X") +_JOINS: tuple[tuple[str, str], ...] = ( + ("JOIN", " ON TRUE"), + ("LEFT JOIN", " ON TRUE"), + ("RIGHT JOIN", " ON TRUE"), + ("FULL OUTER JOIN", " ON TRUE"), + ("LEFT OUTER JOIN", " ON TRUE"), + ("INNER JOIN", " ON TRUE"), + ("CROSS JOIN", ""), +) +_OUTPUT_NAMES: tuple[str, ...] = ( + "c{index}", "C{index}", '"Mx{index}"', "status", "qty", "dup", "Dup", '"Größe"', + '"STRASSE"', '"straße"', "ıd", +) # fmt: skip +_STARS: tuple[str, ...] = ( + "*", + "{alias}.*", + "* EXCLUDE (status)", + "* EXCLUDE (order_id, qty)", + "* REPLACE (1 AS qty)", +) +_SET_OPERATIONS: tuple[str, ...] = ( + "UNION ALL", + "UNION", + "UNION ALL BY NAME", + "EXCEPT", + "INTERSECT", +) +_FACT_KINDS: tuple[str, ...] = ("types", "nullability", "direct", "non_null") +_CTE_NAMES: tuple[str, ...] = ("cte{index}", "Cte{index}", '"Cte{index}"', "base", "orders") + + +def _quoted(rng: random.Random, name: str) -> str: + return rng.choices((f'"{name}"', name.upper(), name.lower(), name), weights=(10, 10, 5, 75))[0] + + +def _column(rng: random.Random, columns: list[str]) -> str: + return _quoted(rng, rng.choice(columns)) + + +def _nested(rng: random.Random, columns: list[str], depth: int) -> str: + return _expression(rng=rng, columns=columns, depth=depth + 1) + + +_LEAVES: tuple[Generate, ...] = ( + lambda rng, columns, depth: _column(rng, columns), + lambda rng, columns, depth: rng.choice(_LITERALS), +) +_COMPOUNDS: tuple[Generate, ...] = ( + lambda rng, columns, depth: _column(rng, columns), + lambda rng, columns, depth: _column(rng, columns), + lambda r, c, d: f"CAST({_nested(r, c, d)} AS {r.choice(_TYPES)})", + lambda r, c, d: f"TRY_CAST({_nested(r, c, d)} AS {r.choice(_TYPES)})", + lambda r, c, d: f"{_nested(r, c, d)}::{r.choice(('INT', 'DECIMAL(5, 1)', 'VARCHAR', 'TEXT'))}", + lambda rng, columns, depth: rng.choice(_LITERALS), + lambda r, c, d: ( + f"CASE WHEN {_nested(r, c, d)} THEN {_nested(r, c, d)} ELSE {_nested(r, c, d)} END" + ), + lambda r, c, d: ( + f"CASE {_nested(r, c, d)} WHEN 1 THEN {_nested(r, c, d)} WHEN 2 THEN {_nested(r, c, d)} END" + ), + lambda r, c, d: f"CASE WHEN {_nested(r, c, d)} THEN {_nested(r, c, d)} END", + lambda r, c, d: f"COALESCE({_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"COALESCE({_nested(r, c, d)}, {_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"NULLIF({_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"IF({_nested(r, c, d)}, {_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"IFF({_nested(r, c, d)}, {_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"UPPER({_nested(r, c, d)})", + lambda r, c, d: f"LOWER({_nested(r, c, d)})", + lambda r, c, d: f"{_nested(r, c, d)} || {_nested(r, c, d)}", + lambda r, c, d: f"SUBSTRING({_nested(r, c, d)}, 1, 2)", + lambda r, c, d: f"{r.choice(('MAX', 'MIN', 'SUM', 'AVG', 'COUNT'))}({_nested(r, c, d)})", + lambda r, c, d: f"MAX({_nested(r, c, d)}) OVER (PARTITION BY {_column(r, c)})", + lambda r, c, d: f"ROW_NUMBER() OVER (ORDER BY {_column(r, c)})", + lambda r, c, d: f"{_nested(r, c, d)} {r.choice(('>', '=', '<>', 'LIKE'))} {_nested(r, c, d)}", + lambda r, c, d: f"{_nested(r, c, d)} IS NULL", + lambda r, c, d: f"{_nested(r, c, d)} IS NOT NULL", + lambda r, c, d: f"{_nested(r, c, d)} {r.choice(('+', '*', '/'))} {_nested(r, c, d)}", + lambda r, c, d: ( + f"{r.choice(('TO_VARCHAR', 'ABS', 'LENGTH', 'REPLACE', 'CONCAT', 'TO_DATE'))}" + f"({_nested(r, c, d)}, {_nested(r, c, d)})" + ), + lambda r, c, d: f"LENGTH({_nested(r, c, d)})", + lambda r, c, d: ( + f"{r.choice(('GREATEST', 'CONCAT_WS', 'DECODE'))}({_nested(r, c, d)}, " + f"{_nested(r, c, d)}, {_nested(r, c, d)})" + ), + lambda r, c, d: f"{_nested(r, c, d)} IN ({_nested(r, c, d)}, {_nested(r, c, d)})", + lambda r, c, d: f"[{_nested(r, c, d)}, {_nested(r, c, d)}]", +) + + +def _expression(*, rng: random.Random, columns: list[str], depth: int) -> str: + builders: tuple[Generate, ...] = (_LEAVES, _COMPOUNDS)[depth < _MAX_DEPTH] + return rng.choice(builders)(rng, columns, depth) + + +def _star_projection( + rng: random.Random, aliases: list[str], columns: list[str], index: int +) -> tuple[str, list[str]]: + return rng.choice(_STARS).format(alias=aliases[0]), list(columns) + + +def _column_projection( + rng: random.Random, aliases: list[str], columns: list[str], index: int +) -> tuple[str, list[str]]: + column: str = rng.choice(columns) + qualifier: str = rng.choices(("", f"{rng.choice(aliases)}."), weights=(6, 4))[0] + return f"{qualifier}{_quoted(rng, column)}", [column] + + +def _expression_projection( + rng: random.Random, aliases: list[str], columns: list[str], index: int +) -> tuple[str, list[str]]: + name: str = rng.choice(_OUTPUT_NAMES).format(index=index) + return f"{_expression(rng=rng, columns=columns, depth=0)} AS {name}", [name.strip('"')] + + +_PROJECTIONS: tuple[Callable[..., tuple[str, list[str]]], ...] = ( + _star_projection, + _column_projection, + _expression_projection, +) + + +def _predicate(rng: random.Random, aliases: list[str], columns: list[str]) -> str: + qualifier: str = rng.choice(("", f"{rng.choice(aliases)}.")) + column: str = f"{qualifier}{_column(rng, columns)}" + return rng.choice( + ( + f"{column} IS NOT NULL", + f"({column} IS NOT NULL)", + f"{column} > 1", + f"NOT {column} IS NULL", + ) + ) + + +def _select( + *, rng: random.Random, relations: dict[str, list[str]], nests: bool +) -> tuple[str, list[str]]: + first: str = rng.choice(list(relations)) + alias_sql, alias = rng.choice(((("", first)), (" a", "a"), (" AS A", "A"), (" t1", "t1"))) + columns: list[str] = list(relations[first]) + aliases: list[str] = [alias] + joins: list[str] = [] + for _ in range(rng.choice((0, 0, 1, 1, 2))): + other: str = rng.choice(list(relations)) + join_alias: str = rng.choice(_ALIASES) + join, condition = rng.choice(_JOINS) + joins.append(f"\n{join} {_quoted(rng, other)} AS {join_alias}{condition}") + columns.extend(relations[other]) + aliases.append(join_alias) + projections: list[str] = [] + outputs: list[str] = [] + for index in range(rng.randint(1, 5)): + projection, names = rng.choices(_PROJECTIONS, weights=(12, 33, 55))[0]( + rng, aliases, columns, index + ) + projections.append(projection) + outputs.extend(names) + predicates: list[str] = [_predicate(rng, aliases, columns) for _ in range(rng.randint(1, 3))] + where: str = rng.choices( + ("", "\nWHERE " + rng.choice((" AND ", " OR ", " AND ")).join(predicates)), + weights=(3, 7), + )[0] + group: str = rng.choices(("", "\nGROUP BY 1"), weights=(9, 1))[0] + body: str = ( + f"SELECT {', '.join(projections)}\nFROM {_quoted(rng, first)}{alias_sql}" + f"{''.join(joins)}{where}{group}" + ) + operation: Callable[[], str] = rng.choices( + (lambda: "", lambda: _set_operation(rng=rng, relations=relations)), weights=(85, 15) + )[0] + selected: str = f"{body}{operation()}" + nested: bool = nests and rng.random() < 0.15 + return ( + lambda: (selected, outputs), + lambda: _nested_select(rng=rng, relations=relations), + )[nested]() + + +def _set_operation(*, rng: random.Random, relations: dict[str, list[str]]) -> str: + other, _ = _select(rng=rng, relations=relations, nests=False) + return f"\n{rng.choice(_SET_OPERATIONS)}\n{other}" + + +def _nested_select(*, rng: random.Random, relations: dict[str, list[str]]) -> tuple[str, list[str]]: + inner, outputs = _select(rng=rng, relations=relations, nests=False) + return f"WITH inner_cte AS ({inner})\nSELECT * FROM inner_cte", outputs + + +def generated_cte_query(*, rng: random.Random) -> str: + """A query of one to three CTEs over typed inputs and an outer select reading them.""" + + relations: dict[str, list[str]] = {table: list(columns) for table, columns in _SCHEMAS.items()} + ctes: list[str] = [] + for index in range(rng.randint(1, 3)): + body, outputs = _select(rng=rng, relations=relations, nests=True) + name: str = rng.choice(_CTE_NAMES).format(index=index) + column_aliases: str = rng.choices(("", " (x, y)"), weights=(93, 7))[0] + ctes.append(f"{name}{column_aliases} AS (\n{body}\n)") + relations[name.strip('"')] = outputs or ["order_id"] + cte_relations: dict[str, list[str]] = dict( + filter(lambda item: item[0] not in _SCHEMAS or rng.random() < 0.2, relations.items()) + ) + outer, _ = _select(rng=rng, relations=cte_relations or relations, nests=False) + return "WITH " + ",\n".join(ctes) + "\n" + outer + + +def generated_cte_fact_query(*, rng: random.Random) -> CteFactQuery: + """A generated query under one adapter's profile, with enrichment's recovery gates.""" + + return CteFactQuery( + sql=generated_cte_query(rng=rng), + profile=rng.choice(PROFILES), + recover=rng.random() < 0.9, + null_filter=rng.random() < 0.8, + ) + + +def python_cte_facts(*, query: CteFactQuery) -> CteFactView: + """Python's recovered facts, as enrichment computes them, or what it raises.""" + + analysis: dict[str, Any] = { + "cteFacts": [1][: int(query.recover)], + "columnUses": [_NULL_FILTER_USE][: int(query.null_filter)], + } + dialect: str | None = query.profile.sql_analysis_dialect + try: + types, nullability, direct, parsed = _polyglot_cte_passthrough_facts( + polyglot_module=import_polyglot(), + cleaned_sql=query.sql, + dialect=dialect, + column_types_by_table=_SCHEMAS, + column_nullability_by_table=_INPUT_NULLABILITY, + inference_profile=query.profile, + analysis=analysis, + resolvers=_RESOLVERS, + ) + non_null: frozenset[str] = _polyglot_filtered_non_null_outputs( + polyglot_module=import_polyglot(), + cleaned_sql=query.sql, + dialect=dialect, + analysis=analysis, + column_nullability_by_table=_INPUT_NULLABILITY, + parsed=parsed, + ) + except Exception as error: # noqa: BLE001 - native must not answer where Python raises + return (type(error).__name__, str(error)) + return ( + list(types.items()), + [(name, value.value) for name, value in nullability.items()], + sorted(direct), + sorted(non_null), + ) + + +def native_cte_facts(*, query: CteFactQuery) -> tuple[str | None, CteFactView]: + """Native recovery's deferral reason, or None and its facts.""" + + deferral, types, nullability, direct, non_null = native_module._oracle_cte_fact_recovery( + ( + query.sql, + query.profile.sql_analysis_dialect or "generic", + _INPUT_SHAPES, + list(query.profile.function_return_types.items()), + nullability_rule_rows(query.profile), + query.recover, + query.null_filter, + ) + ) + return deferral, (types, nullability, direct, non_null) + + +def compare_cte_facts(*, query: CteFactQuery, parity: CteFactParity) -> None: + """Record both recoveries of `query` where native answers, and what each recovered.""" + + deferral, native = native_cte_facts(query=query) + answered: list[CteFactView] = [native][: int(deferral is None)] + python: list[CteFactView] = [python_cte_facts(query=query) for _ in answered] + parity.counts.update( + [f"deferred:{str(deferral).partition(' ')[0]}"][: int(deferral is not None)] + ) + parity.counts["compared"] += len(answered) + for index, kind in enumerate(_FACT_KINDS): + parity.counts[f"recovered_{kind}"] += sum(bool(view[index]) for view in answered) + parity.queries.extend((query.sql, query.profile.sql_analysis_dialect) for _ in answered) + parity.python.extend(python) + parity.native.extend(answered) diff --git a/tests/integration/src/sqlbuild/compiler/analysis_session/_test_types.py b/tests/integration/src/sqlbuild/compiler/analysis_session/_test_types.py index f3ea3a0aac..c0bf2ae4fd 100644 --- a/tests/integration/src/sqlbuild/compiler/analysis_session/_test_types.py +++ b/tests/integration/src/sqlbuild/compiler/analysis_session/_test_types.py @@ -15,6 +15,7 @@ class GeneratedAnalysisParityTestCase: expected_minimum_native: int expected_minimum_expression_shapes: int expected_minimum_pivot_proofs: int + expected_minimum_python_cte_recoveries: int expected_minimum_proven_pivots: int expected_maximum_enrichment_deferrals: int expected_minimum_native_enrichments: int @@ -48,4 +49,31 @@ class StandalonePivotProofTestCase: description: str analysed_models: frozenset[str] expected_native_proofs: int + expected_session_proofs: int expected_proven_by_model: dict[str, bool | None] + + +@dataclass(frozen=True) +class SharedAnalysisTestCase: + """Models whose equal queries share one analysis, some inexact and so re-analysed alone.""" + + description: str + regions: tuple[str, ...] + inexact_regions: tuple[str, ...] + dialects: tuple[str | None, ...] + expected_analysed: int + expected_shared: int + expected_reanalysed: int + expected_unshared: int + expected_column_values: int + + +@dataclass(frozen=True) +class CteFactRecoveryParityTestCase: + """Seeded CTE queries whose native and Python CTE fact recoveries must agree.""" + + description: str + seed: int + count: int + expected_minimum_compared: int + expected_minimum_recovered: dict[str, int] diff --git a/tests/integration/src/sqlbuild/compiler/analysis_session/helpers.py b/tests/integration/src/sqlbuild/compiler/analysis_session/helpers.py index 47095774c0..8b4d354ca2 100644 --- a/tests/integration/src/sqlbuild/compiler/analysis_session/helpers.py +++ b/tests/integration/src/sqlbuild/compiler/analysis_session/helpers.py @@ -15,6 +15,7 @@ import sqlbuild._native as native_module import sqlbuild.compiler.analysis_session.classes.native_model_analysis as native_model_analysis +import sqlbuild.compiler.compile._helpers.analysis.compact as compact_analysis import sqlbuild.compiler.compile._helpers.assembly.project as project_assembly import sqlbuild.compiler.compile._helpers.native_stages.assembly as native_stage_assembly from sqlbuild.adapter.contract.models import ExpressionInferenceProfile @@ -25,10 +26,14 @@ from sqlbuild.compiler.analysis_session.main._infer_native_expression_source_shapes import ( infer_native_expression_source_shapes, ) -from sqlbuild.compiler.analysis_session.main._prove_native_dynamic_contract import ( - prove_native_dynamic_contract, +from sqlbuild.compiler.analysis_session.main._prove_native_dynamic_contracts import ( + prove_native_dynamic_contracts, +) +from sqlbuild.compiler.analysis_session.models import ( + NativeModelAnalyses, + NativeModelAnalysisRequest, + NativePivotTables, ) -from sqlbuild.compiler.analysis_session.models import NativeModelAnalysisRequest from sqlbuild.compiler.compile._helpers.assembly.semantic_shapes import ( get_expression_source_shapes, ) @@ -40,6 +45,7 @@ CompiledLineageColumnFact, CompileProjectInputs, DynamicColumnContractProof, + InferredColumn, ModelSqlAnalysis, ) from sqlbuild.compiler.discovery.main.discover import discover_project_inputs @@ -171,6 +177,8 @@ def _pivot_models(rng: random.Random) -> dict[str, str]: return files +_PYTHON_CTE_RECOVERY: Callable[..., Any] = compact_analysis._polyglot_cte_passthrough_facts + type _Relation = tuple[str, tuple[str, ...]] type _Template = Callable[[random.Random, list[_Relation]], tuple[str, str, tuple[str, ...]]] @@ -258,6 +266,35 @@ def _contract(rng: random.Random, inputs: list[_Relation]) -> tuple[str, str, tu return header, sql, ("contract_key", "contract_label") +_CTE_CONTRACT_BODIES: tuple[str, ...] = ( + "WITH base AS (\n SELECT {a}, {b} FROM {left}\n)\nSELECT {a}, {b} FROM base", + "WITH base AS (\n SELECT CAST({a} AS VARCHAR(12)) AS label, COALESCE({b}, {a}) AS filled,\n" + " 'fixed' AS tag, CAST(1.5 AS DECIMAL(10, 2)) AS ratio, {a} IS NULL AS missing\n" + " FROM {left}\n WHERE {a} IS NOT NULL\n)\n" + "SELECT label, filled, tag, ratio, missing FROM base", + "WITH base AS (\n SELECT CASE WHEN {a} IS NULL THEN 'none' ELSE 'some' END AS state,\n" + " UPPER(CAST({b} AS VARCHAR)) AS upper_b, CAST({a} AS TEXT) || '-x' AS joined\n" + " FROM {left}\n)\nSELECT state, upper_b, joined FROM base", + "WITH unioned AS (\n SELECT {a} AS shared FROM {left}\n UNION ALL\n" + " SELECT {c} FROM {right}\n)\nSELECT shared FROM unioned", + "WITH base AS (\n SELECT * EXCLUDE ({a}) FROM {left}\n)\nSELECT {b} FROM base", + "WITH lhs AS (\n SELECT {a}, {b} FROM {left}\n),\nrhs AS (\n SELECT {c} FROM {right}\n)\n" + "SELECT l.{a}, r.{c}\nFROM lhs l\nLEFT JOIN rhs r ON l.{a} = r.{c}", + "WITH outer_cte AS (\n WITH inner_cte AS (SELECT {a}, {b} FROM {left})\n" + " SELECT {a}, {b} FROM inner_cte\n)\nSELECT {a}, {b} FROM outer_cte", + "WITH base AS (\n SELECT {a}, NULLIF({b}, {b}) AS cleared, MAX({b}) AS latest FROM {left}\n" + " GROUP BY {a}\n)\nSELECT {a}, cleared, latest FROM base WHERE {a} IS NOT NULL", +) + + +def _cte_contract(rng: random.Random, inputs: list[_Relation]) -> tuple[str, str, tuple[str, ...]]: + (left, left_columns), (right, right_columns) = inputs[0], inputs[-1] + first, second = rng.sample(list(left_columns), k=2) + body: str = rng.choice(_CTE_CONTRACT_BODIES) + sql: str = body.format(a=first, b=second, c=right_columns[0], left=left, right=right) + return " contract enforced,\n", sql, (first, second) + + def _unknown_column( rng: random.Random, inputs: list[_Relation] ) -> tuple[str, str, tuple[str, ...]]: @@ -282,6 +319,7 @@ def _subquery(rng: random.Random, inputs: list[_Relation]) -> tuple[str, str, tu _aggregate, _quoted, _contract, + _cte_contract, _unknown_column, _subquery, ) @@ -301,19 +339,28 @@ def pivot_project_files() -> dict[str, str]: } -def native_pivot_proofs( - *, monkeypatch: pytest.MonkeyPatch -) -> list[DynamicColumnContractProof | None]: - """Record every standalone native pivot proof assembly takes, failing any wheel pivot proof.""" +@dataclass +class NativePivotProofs: + """Every native pivot proof assembly took, and how many a finished session proved.""" + + proofs: list[DynamicColumnContractProof | None] = field(default_factory=list) + session_proofs: int = 0 + + +def native_pivot_proofs(*, monkeypatch: pytest.MonkeyPatch) -> NativePivotProofs: + """Record every batch of native pivot proofs assembly takes, failing any wheel pivot proof.""" - proofs: list[DynamicColumnContractProof | None] = [] - native_proof: Callable[..., DynamicColumnContractProof | None] = ( - native_stage_assembly.prove_native_dynamic_contract + recorded_proofs: NativePivotProofs = NativePivotProofs() + native_proofs: Callable[..., tuple[DynamicColumnContractProof | None, ...]] = ( + native_stage_assembly.prove_native_dynamic_contracts ) - def recorded(**keywords: Any) -> DynamicColumnContractProof | None: - proofs.append(native_proof(**keywords)) - return proofs[-1] + def recorded(**keywords: Any) -> tuple[DynamicColumnContractProof | None, ...]: + proofs: tuple[DynamicColumnContractProof | None, ...] = native_proofs(**keywords) + recorded_proofs.proofs.extend(proofs) + proven: int = sum(proof is not None for proof in proofs) + recorded_proofs.session_proofs += proven * (keywords["session"] is not None) + return proofs python_proof: Callable[..., DynamicColumnContractProof | None] = ( project_assembly.analyze_dynamic_column_contract @@ -323,9 +370,9 @@ def wheel_not_expected(**keywords: Any) -> DynamicColumnContractProof | None: assert not keywords["families"], "the Python wheel proved a pivot native should prove" return python_proof(**keywords) - monkeypatch.setattr(native_stage_assembly, "prove_native_dynamic_contract", recorded) + monkeypatch.setattr(native_stage_assembly, "prove_native_dynamic_contracts", recorded) monkeypatch.setattr(project_assembly, "analyze_dynamic_column_contract", wheel_not_expected) - return proofs + return recorded_proofs def generated_analysis_files(*, rng: random.Random, model_count: int) -> dict[str, str]: @@ -349,6 +396,60 @@ def generated_analysis_files(*, rng: random.Random, model_count: int) -> dict[st return files +def shared_analysis_files( + *, regions: tuple[str, ...], inexact_regions: tuple[str, ...] +) -> dict[str, str]: + """Equal regional models and rollups, missing-column readers and one unshared summary.""" + + regional: dict[str, str] = { + f"models/staging/orders_{region}.sql": ( + f'MODEL (description "Orders in {region}");\n\n' + 'SELECT order_id, customer_id, amount FROM __source("raw_orders")\n' + ) + for region in regions + } + rollups: dict[str, str] = { + f"models/marts/totals_{region}.sql": ( + f'MODEL (description "Customer totals in {region}");\n\n' + "SELECT customer_id, SUM(amount) AS total_amount\n" + f'FROM __ref("orders_{region}")\nGROUP BY customer_id\n' + ) + for region in regions + } + inexact: dict[str, str] = { + f"models/marts/missing_{region}.sql": ( + f'MODEL (description "Orders in {region} with an unknown column");\n\n' + f'SELECT customer_id, missing_column FROM __ref("orders_{region}")\n' + ) + for region in inexact_regions + } + return { + "sqlbuild_project.toml": _PROJECT_TOML, + "sources/raw.yml": _SOURCES, + **regional, + **rollups, + **inexact, + "models/marts/orders_summary.sql": ( + 'MODEL (description "Order count");\n\n' + f'SELECT COUNT(*) AS order_count FROM __ref("orders_{regions[0]}")\n' + ), + } + + +def started_sessions(*, monkeypatch: pytest.MonkeyPatch) -> list[Any]: + """Record every native session started; return the list they are appended to.""" + + started: list[Any] = [] + original: Callable[..., Any] = native_module.start_model_analysis_session + + def start(catalog: object, request: tuple[object, ...]) -> Any: + started.append(original(catalog, request)) + return started[-1] + + monkeypatch.setattr(native_module, "start_model_analysis_session", start) + return started + + def compile_inputs(*, project_dir: Path, files: dict[str, str]) -> CompileProjectInputs: """Write a project and attach its compile inputs with the DuckDB compile context.""" @@ -373,9 +474,13 @@ class AnalysisParity: analysed_models: int = 0 expression_shapes: int = 0 pivot_proofs: int = 0 + python_cte_recoveries: int = 0 standalone_proofs: int = 0 + session_proofs: int = 0 proven_pivots: int = 0 native_enrichments: int = 0 + native_column_objects: int = 0 + native_column_values: int = 0 def compare_analyses( @@ -387,15 +492,17 @@ def compare_analyses( ) -> None: """Assemble `inputs`, analysing every seam call with both engines into `parity`.""" + sessions: list[Any] = [] + def models_by_both( *, python_analysis: partial[dict[str, ModelSqlAnalysis]], dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], - ) -> dict[str, ModelSqlAnalysis]: + ) -> tuple[dict[str, ModelSqlAnalysis], Any]: keywords: dict[str, Any] = {**python_analysis.keywords, "analysis_cache": None} profile: ExpressionInferenceProfile = keywords["inference_profile"] native_catalog: Any = profile.binding_catalog.with_relations({}) - native: dict[str, ModelSqlAnalysis] | None = analyze_native_model_sql( + native_result: NativeModelAnalyses | None = analyze_native_model_sql( request=NativeModelAnalysisRequest( **{ **keywords, @@ -404,7 +511,20 @@ def models_by_both( dynamic_families_by_table=dynamic_families_by_table, ) ) - python: dict[str, ModelSqlAnalysis] = python_analysis.func(**keywords) + native: dict[str, ModelSqlAnalysis] | None = getattr(native_result, "analyses", None) + sessions.append(getattr(native_result, "session", None)) + with monkeypatch.context() as patch: + patch.setattr( + compact_analysis, + "_polyglot_cte_passthrough_facts", + partial(_counted_cte_recovery, parity=parity), + ) + python: dict[str, ModelSqlAnalysis] = python_analysis.func(**keywords) + columns: list[InferredColumn] = list( + chain.from_iterable(map(_native_columns, (native or {}).values())) + ) + parity.native_column_objects += len(set(map(id, columns))) + parity.native_column_values += len(set(columns)) parity.analysed_models += len(python) _append(parity, "model analyses", _analysis_views(python), _analysis_views(native)) _append( @@ -413,25 +533,32 @@ def models_by_both( _catalog_view(profile.binding_catalog), _catalog_view(native_catalog), ) - return native or python + return native or python, sessions[-1] def proofs_by_both( *, sql_analysis: ModelSqlAnalysis | None, + native_proof: DynamicColumnContractProof | None, python_proof: partial[DynamicColumnContractProof | None], ) -> DynamicColumnContractProof | None: native: DynamicColumnContractProof | None = getattr( sql_analysis, "dynamic_column_contract", None ) python: DynamicColumnContractProof | None = python_proof() - standalone: DynamicColumnContractProof | None = prove_native_dynamic_contract( - **python_proof.keywords + session: Any = (sessions or [None])[-1] + standalone: DynamicColumnContractProof | None = _batched_proof( + session=None, python_proof=python_proof ) + in_session: DynamicColumnContractProof | None = _batched_proof( + session=session, python_proof=python_proof + ) + parity.session_proofs += in_session is not None and session is not None parity.pivot_proofs += native is not None parity.proven_pivots += native is not None and native.output_proven parity.standalone_proofs += standalone is not None _append(parity, "dynamic pivot proof", python, native or python) _append(parity, "standalone dynamic pivot proof", python, standalone or python) + _append(parity, "session dynamic pivot proof", python, in_session or python) return python def shapes_by_both( @@ -485,13 +612,13 @@ def captured( *, python_analysis: partial[dict[str, ModelSqlAnalysis]], dynamic_families_by_table: dict[str, tuple[SchemaDynamicColumnFamily, ...]], - ) -> dict[str, ModelSqlAnalysis]: + ) -> tuple[dict[str, ModelSqlAnalysis], None]: requests.append( NativeModelAnalysisRequest( **python_analysis.keywords, dynamic_families_by_table=dynamic_families_by_table ) ) - return python_analysis() + return python_analysis(), None with monkeypatch.context() as patch, suppress(CompileInputError): patch.setattr(project_assembly, "analyze_model_sql_by_engine", captured) @@ -515,6 +642,33 @@ def deferral_kinds(record_dir: Path) -> Counter[str]: return Counter(f"{record['site']}:{record['kind']}" for record in records) +def _native_columns(analysis: ModelSqlAnalysis) -> tuple[InferredColumn, ...]: + return analysis.polyglot_analysis.columns or () + + +def _counted_cte_recovery(*, parity: AnalysisParity, **arguments: Any) -> Any: + recovered: Any = _PYTHON_CTE_RECOVERY(**arguments) + parity.python_cte_recoveries += bool(recovered[2]) + return recovered + + +def _batched_proof( + *, session: Any, python_proof: partial[DynamicColumnContractProof | None] +) -> DynamicColumnContractProof | None: + keywords: dict[str, Any] = python_proof.keywords + return prove_native_dynamic_contracts( + session=session, + tables=NativePivotTables( + dialect=keywords["dialect"], + column_types_by_table=keywords["column_types_by_table"], + authoritative_column_types_by_table=keywords["authoritative_column_types_by_table"], + column_nullability_by_table=keywords["column_nullability_by_table"], + dynamic_families_by_table=keywords["dynamic_families_by_table"], + ), + models=((keywords["query_sql"], keywords["families"]),), + )[0] + + def _append(parity: AnalysisParity, name: str, python: object, native: object) -> None: parity.names.append(name) parity.python.append(python) diff --git a/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_cte_fact_recovery.py b/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_cte_fact_recovery.py new file mode 100644 index 0000000000..119e8e0c71 --- /dev/null +++ b/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_cte_fact_recovery.py @@ -0,0 +1,56 @@ +"""Native CTE fact recovery equals Python's recovery on seeded queries, query by query.""" + +from __future__ import annotations + +import random +from collections import Counter + +import pytest + +from tests.integration.src.sqlbuild.compiler.analysis_session._test_helpers import ( + CteFactParity, + compare_cte_facts, + generated_cte_fact_query, +) +from tests.integration.src.sqlbuild.compiler.analysis_session._test_types import ( + CteFactRecoveryParityTestCase, +) +from tests.integration.src.sqlbuild.compiler.helpers import mismatches + + +@pytest.mark.parametrize( + "test_case", + [ + CteFactRecoveryParityTestCase( + description="casts, CASE, COALESCE, IF/IFF, adapter rules, set operations, stars, joins, filters", + seed=20261009, + count=5000, + expected_minimum_compared=4319, + expected_minimum_recovered={ + "types": 1243, + "nullability": 417, + "direct": 859, + "non_null": 38, + }, + ) + ], + ids=lambda case: case.description, +) +def test_given_seeded_cte_queries_when_recovering_facts_natively_then_matches_python( + test_case: CteFactRecoveryParityTestCase, +) -> None: + rng: random.Random = random.Random(test_case.seed) + parity: CteFactParity = CteFactParity(queries=[], python=[], native=[], counts=Counter()) + for _ in range(test_case.count): + compare_cte_facts(query=generated_cte_fact_query(rng=rng), parity=parity) + + assert mismatches(inputs=parity.queries, expected=parity.python, actual=parity.native) == [] + assert parity.counts["compared"] >= test_case.expected_minimum_compared + assert { + kind: parity.counts[f"recovered_{kind}"] >= minimum + for kind, minimum in test_case.expected_minimum_recovered.items() + } == dict.fromkeys(test_case.expected_minimum_recovered, True) + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_model_analysis.py b/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_model_analysis.py index 4e9527ea64..ff770ec691 100644 --- a/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_model_analysis.py +++ b/tests/integration/src/sqlbuild/compiler/analysis_session/test_native_model_analysis.py @@ -6,6 +6,7 @@ from collections import Counter from dataclasses import replace from pathlib import Path +from typing import Any import pytest @@ -18,7 +19,6 @@ from sqlbuild.compiler.compile.models import ( CompiledProject, CompileProjectInputs, - DynamicColumnContractProof, ) from sqlbuild.compiler.frontier.constants import COMPILER_ENGINE_ENV_VAR from sqlbuild.compiler.frontier.types import CompilerEngine @@ -27,11 +27,13 @@ AnalysisFallbackTestCase, GeneratedAnalysisParityTestCase, SessionFailureTestCase, + SharedAnalysisTestCase, StandalonePivotProofTestCase, ) from tests.integration.src.sqlbuild.compiler.analysis_session.helpers import ( AnalysisParity, FailingProvideSession, + NativePivotProofs, analysis_request, compare_analyses, compile_inputs, @@ -40,6 +42,8 @@ generated_analysis_files, native_pivot_proofs, pivot_project_files, + shared_analysis_files, + started_sessions, ) from tests.integration.src.sqlbuild.compiler.helpers import mismatches @@ -54,7 +58,7 @@ "test_case", [ GeneratedAnalysisParityTestCase( - description="stars, CTEs, set operations, untyped inputs, contracts, contract CTEs, pivots", + description="stars, CTEs, CTE facts, set operations, untyped inputs, contracts, pivots", seed=20261008, count=6, model_count=24, @@ -62,8 +66,9 @@ expected_minimum_native=500, expected_minimum_expression_shapes=40, expected_minimum_pivot_proofs=80, + expected_minimum_python_cte_recoveries=40, expected_minimum_proven_pivots=12, - expected_maximum_enrichment_deferrals=120, + expected_maximum_enrichment_deferrals=0, expected_minimum_native_enrichments=90, ) ], @@ -90,19 +95,82 @@ def test_given_generated_projects_when_analysing_natively_then_matches_python( assert mismatches(inputs=parity.names, expected=parity.python, actual=parity.native) == [] assert kinds["analysis_session:session"] == kinds["analysis_session:expression_shapes"] == 0 assert kinds["analysis_session:dynamic_pivot"] == 0 + assert parity.python_cte_recoveries >= test_case.expected_minimum_python_cte_recoveries assert ( - parity.analysed_models - kinds["analysis_session:legacy_analysis"] + parity.analysed_models + - kinds["analysis_session:legacy_analysis"] + - kinds["analysis_session:input_enrichment"] >= test_case.expected_minimum_native ) assert parity.expression_shapes >= test_case.expected_minimum_expression_shapes assert parity.pivot_proofs >= test_case.expected_minimum_pivot_proofs assert parity.standalone_proofs >= test_case.expected_minimum_pivot_proofs + assert parity.session_proofs >= test_case.expected_minimum_pivot_proofs assert parity.proven_pivots >= test_case.expected_minimum_proven_pivots assert ( kinds["analysis_session:input_enrichment"] <= test_case.expected_maximum_enrichment_deferrals ) assert parity.native_enrichments >= test_case.expected_minimum_native_enrichments + assert parity.native_column_objects == parity.native_column_values > 0 + + +@pytest.mark.parametrize( + "test_case", + [ + SharedAnalysisTestCase( + description="equal regional queries, missing-column readers and a unique summary", + regions=("east", "west", "north", "south"), + inexact_regions=("east", "west", "north"), + dialects=("duckdb", "snowflake"), + expected_analysed=24, + expected_shared=22, + expected_reanalysed=6, + expected_unshared=2, + expected_column_values=12, + ) + ], + ids=lambda case: case.description, +) +def test_given_equal_model_queries_when_analysing_natively_then_shares_and_matches_python( + test_case: SharedAnalysisTestCase, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + record_dir: Path = tmp_path / "records" + monkeypatch.setenv(ANALYSIS_RECORD_DIR_ENV_VAR, str(record_dir)) + inputs: CompileProjectInputs = compile_inputs( + project_dir=tmp_path / "project", + files=shared_analysis_files( + regions=test_case.regions, inexact_regions=test_case.inexact_regions + ), + ) + sessions: list[Any] = started_sessions(monkeypatch=monkeypatch) + parity: AnalysisParity = AnalysisParity() + + _ = [ + compare_analyses(inputs=inputs, dialect=dialect, parity=parity, monkeypatch=monkeypatch) + for dialect in test_case.dialects + ] + + shared: int = sum(session.sharing[0] for session in sessions) + + assert mismatches(inputs=parity.names, expected=parity.python, actual=parity.native) == [] + assert ( + parity.analysed_models, + shared, + sum(session.sharing[1] for session in sessions), + parity.analysed_models - shared, + deferral_kinds(record_dir), + parity.native_column_objects, + parity.native_column_values, + ) == ( + test_case.expected_analysed, + test_case.expected_shared, + test_case.expected_reanalysed, + test_case.expected_unshared, + Counter(), + test_case.expected_column_values, + test_case.expected_column_values, + ) @pytest.mark.parametrize( @@ -199,12 +267,24 @@ def test_given_session_failure_after_deferrals_when_analysing_then_records_only_ description="a selection that leaves the pivots out of model analysis", analysed_models=frozenset({"orders_list"}), expected_native_proofs=2, + expected_session_proofs=2, expected_proven_by_model={ "orders_list": None, "status_amounts": True, "status_passthrough": True, }, - ) + ), + StandalonePivotProofTestCase( + description="no model analysis, so the proofs run without a session", + analysed_models=frozenset(), + expected_native_proofs=2, + expected_session_proofs=0, + expected_proven_by_model={ + "orders_list": None, + "status_amounts": True, + "status_passthrough": True, + }, + ), ], ids=lambda case: case.description, ) @@ -215,7 +295,7 @@ def test_given_unanalysed_pivot_model_when_assembling_then_native_proves_it_with project_dir=tmp_path / "project", files=pivot_project_files() ) monkeypatch.setenv(COMPILER_ENGINE_ENV_VAR, CompilerEngine.NATIVE_PREVIEW.value) - proofs: list[DynamicColumnContractProof | None] = native_pivot_proofs(monkeypatch=monkeypatch) + recorded: NativePivotProofs = native_pivot_proofs(monkeypatch=monkeypatch) project: CompiledProject = assemble_compiled_project( inputs=inputs, @@ -224,13 +304,19 @@ def test_given_unanalysed_pivot_model_when_assembling_then_native_proves_it_with ) assert ( - all(proof is not None for proof in proofs), - len(proofs), + all(proof is not None for proof in recorded.proofs), + len(recorded.proofs), + recorded.session_proofs, { model.name: getattr(model.dynamic_column_contract, "output_proven", None) for model in project.models }, - ) == (True, test_case.expected_native_proofs, test_case.expected_proven_by_model) + ) == ( + True, + test_case.expected_native_proofs, + test_case.expected_session_proofs, + test_case.expected_proven_by_model, + ) if __name__ == "__main__": diff --git a/tests/integration/src/sqlbuild/compiler/project_assembly/_test_types.py b/tests/integration/src/sqlbuild/compiler/project_assembly/_test_types.py index 680d93254c..1e010ed519 100644 --- a/tests/integration/src/sqlbuild/compiler/project_assembly/_test_types.py +++ b/tests/integration/src/sqlbuild/compiler/project_assembly/_test_types.py @@ -45,3 +45,13 @@ class WindowsEnvironmentTestCase: environment: dict[str, str] seed_schema: str expected_schema: str + + +@dataclass(frozen=True) +class OptOutTestCase: + """Models opting out of required SQL analysis, and which ones parse so Python rejects them.""" + + description: str + models: dict[str, str] + expected_rejected: dict[str, bool] + expected_python_validations: int diff --git a/tests/integration/src/sqlbuild/compiler/project_assembly/helpers.py b/tests/integration/src/sqlbuild/compiler/project_assembly/helpers.py index 05d2a1188c..c8b4ded2df 100644 --- a/tests/integration/src/sqlbuild/compiler/project_assembly/helpers.py +++ b/tests/integration/src/sqlbuild/compiler/project_assembly/helpers.py @@ -15,6 +15,7 @@ from sqlbuild.adapters.duckdb.classes.duckdb_adapter import DuckDbAdapter from sqlbuild.compiler.compile._helpers.assembly import project as project_module from sqlbuild.compiler.compile._helpers.assembly.project import assemble_compiled_project +from sqlbuild.compiler.compile._helpers.diagnostics import sql_analysis_opt_outs from sqlbuild.compiler.compile.constants import COMPILE_INPUT_READS from sqlbuild.compiler.compile.main._build_compile_inputs import build_compile_inputs from sqlbuild.compiler.compile.models import ( @@ -38,6 +39,7 @@ "audit_scope_deps", ) _ASSEMBLY_RECORD_PREFIX: str = "project_assembly:" +_OPT_OUT_VALIDATORS: tuple[str, ...] = ("validate_sql_syntax", "validate_hook_sql_syntax") _ADAPTER_CONTEXT: CompileAdapterContext = CompileAdapterContext( value_renderer=DuckDbAdapter(), collection_rendering=CollectionRendering.VALUE_LIST, @@ -199,6 +201,38 @@ def assembly_view(project: CompiledProject) -> object: ) +def rejected_opt_outs( + *, + project_dir: Path, + files: dict[str, str], + engine: CompilerEngine, + monkeypatch: pytest.MonkeyPatch, +) -> tuple[dict[str, bool], int]: + """Attach `files` with `engine`; return each opt-out's rejection and Python validations.""" + + calls: Counter[str] = Counter() + monkeypatch.setenv(COMPILER_ENGINE_ENV_VAR, engine.value) + with monkeypatch.context() as patch: + _ = [ + patch.setattr( + sql_analysis_opt_outs, + name, + _counted(name=name, function=getattr(sql_analysis_opt_outs, name), calls=calls), + ) + for name in _OPT_OUT_VALIDATORS + ] + inputs: CompileProjectInputs = project_inputs(project_dir=project_dir, files=files) + return ( + { + model_input.model_file.file_path.stem: ( + model_input.rejected_sql_analysis_opt_out is not None + ) + for model_input in inputs.model_inputs + }, + calls.total(), + ) + + def assembly_deferrals(record_dir: Path) -> Counter[str]: """Count the project assembly `site:kind` deferral records below `record_dir`.""" diff --git a/tests/integration/src/sqlbuild/compiler/project_assembly/test_native_project_assembly.py b/tests/integration/src/sqlbuild/compiler/project_assembly/test_native_project_assembly.py index 5b9ef5783e..e88e498591 100644 --- a/tests/integration/src/sqlbuild/compiler/project_assembly/test_native_project_assembly.py +++ b/tests/integration/src/sqlbuild/compiler/project_assembly/test_native_project_assembly.py @@ -19,6 +19,7 @@ AssemblyDeferralTestCase, DeferredAssemblyTestCase, GeneratedAssemblyParityTestCase, + OptOutTestCase, WindowsEnvironmentTestCase, ) from tests.integration.src.sqlbuild.compiler.project_assembly.helpers import ( @@ -29,6 +30,7 @@ project_inputs, python_resource_calls, recorded_assembly, + rejected_opt_outs, seed_yml, windows_environ, ) @@ -37,6 +39,11 @@ 'name = "assembly"\nadapter = "duckdb"\n\n[connection]\ndatabase = ":memory:"\n\n' ) _ORDERS_MODEL: str = 'MODEL (description "Orders");\n\nSELECT 1 AS n\n' +_REQUIRED_ANALYSIS_TOML: str = ( + 'name = "assembly"\nadapter = "duckdb"\n\n' + '[connection]\ndatabase = ":memory:"\n\n[settings]\nrequire_sql_analysis = true\n' +) +_OPT_OUT_HEADER: str = 'MODEL (\n description "Orders",\n sql_analysis false,\n' _SEED_FILES: dict[str, str] = { "seeds/countries.csv": "n\n1\n", "models/orders.sql": _ORDERS_MODEL, @@ -261,3 +268,47 @@ def test_given_windows_environment_when_assembling_natively_then_env_lookups_mat assert python.seeds[0].destination.schema == test_case.expected_schema assert assembly_view(native) == assembly_view(python) assert assembly_deferrals(record_dir) == Counter() + + +@pytest.mark.parametrize( + "test_case", + [ + OptOutTestCase( + description="parseable, unparseable and unparseable-hook opt-outs", + models={ + "models/parses.sql": f"{_OPT_OUT_HEADER});\n\nSELECT 1 AS n\n", + "models/broken_query.sql": f"{_OPT_OUT_HEADER});\n\nSELECT FROM WHERE (\n", + "models/broken_hook.sql": ( + f'{_OPT_OUT_HEADER} post_hooks [inline_sql("SELECT FROM (")],\n);\n\n' + "SELECT 1 AS n\n" + ), + }, + expected_rejected={"broken_hook": False, "broken_query": False, "parses": True}, + expected_python_validations=7, + ) + ], + ids=lambda case: case.description, +) +def test_given_sql_analysis_opt_outs_when_attaching_natively_then_python_rejections_match( + test_case: OptOutTestCase, tmp_path: Path, monkeypatch: pytest.MonkeyPatch +) -> None: + record_dir: Path = tmp_path / "records" + monkeypatch.setenv(ANALYSIS_RECORD_DIR_ENV_VAR, str(record_dir)) + files: dict[str, str] = {"sqlbuild_project.toml": _REQUIRED_ANALYSIS_TOML, **test_case.models} + + python: tuple[dict[str, bool], int] = rejected_opt_outs( + project_dir=tmp_path / "python", + files=files, + engine=CompilerEngine.PYTHON, + monkeypatch=monkeypatch, + ) + native: tuple[dict[str, bool], int] = rejected_opt_outs( + project_dir=tmp_path / "native", + files=files, + engine=CompilerEngine.NATIVE_PREVIEW, + monkeypatch=monkeypatch, + ) + + assert python == (test_case.expected_rejected, test_case.expected_python_validations) + assert native == (test_case.expected_rejected, 0) + assert assembly_deferrals(record_dir) == Counter() diff --git a/tests/integration/src/sqlbuild/compiler/semantic_checks/_test_types.py b/tests/integration/src/sqlbuild/compiler/semantic_checks/_test_types.py index 31dd072d29..10a8a6c3d3 100644 --- a/tests/integration/src/sqlbuild/compiler/semantic_checks/_test_types.py +++ b/tests/integration/src/sqlbuild/compiler/semantic_checks/_test_types.py @@ -40,3 +40,18 @@ class GeneratedMetadataParityTestCase: dialects: tuple[str, ...] expected_minimum_native: int expected_minimum_families: dict[str, int] + + +@dataclass(frozen=True) +class SessionCompletionTestCase: + """Seeded preview compiles whose completion reads analysed models from the native session.""" + + description: str + corpus: str + seed: int + count: int + model_count: int + expected_session_models: int + expected_payload_models: int + expected_proven_outputs: int + expected_minimum_codes: dict[str, int] diff --git a/tests/integration/src/sqlbuild/compiler/semantic_checks/helpers.py b/tests/integration/src/sqlbuild/compiler/semantic_checks/helpers.py index 97ed5ccb0d..8cbb77988d 100644 --- a/tests/integration/src/sqlbuild/compiler/semantic_checks/helpers.py +++ b/tests/integration/src/sqlbuild/compiler/semantic_checks/helpers.py @@ -13,6 +13,7 @@ import sqlbuild._native as native_module import sqlbuild.compiler.compile._helpers.assembly.project as assembly_project +import sqlbuild.compiler.semantic_checks._helpers.stage as semantic_stage from sqlbuild.adapter.contract.models import ExpressionInferenceProfile from sqlbuild.adapters.duckdb.classes.duckdb_adapter import DuckDbAdapter from sqlbuild.compiler.compile._helpers.assembly.metadata_validation import ( @@ -26,10 +27,14 @@ from sqlbuild.compiler.frontier.constants import COMPILER_ENGINE_ENV_VAR from sqlbuild.compiler.pipeline.main.graph import build_project_graph from sqlbuild.compiler.semantic_checks._helpers.metadata import native_metadata_diagnostics +from sqlbuild.compiler.semantic_checks._helpers.payloads import session_fact_models from sqlbuild.compiler.semantic_checks.main._complete_native_semantic_diagnostics import ( complete_native_semantic_diagnostics, ) from sqlbuild.compiler.sql_analysis.models import SqlBindingDiagnostic +from tests.integration.src.sqlbuild.compiler.analysis_session.helpers import ( + generated_analysis_files, +) _RELATIONS: dict[str, tuple[str, ...]] = { '__source("raw_orders")': ( @@ -81,6 +86,7 @@ class SemanticInputs: profile: ExpressionInferenceProfile binding_results: dict[str, tuple[SqlBindingDiagnostic, ...]] resource_sql_analysis: bool + native_session: Any | None = None def _typo(rng: random.Random, column: str) -> str: @@ -173,9 +179,13 @@ def generated_semantic_files( def captured_semantic_inputs( - *, project_dir: Path, files: dict[str, str], monkeypatch: pytest.MonkeyPatch + *, + project_dir: Path, + files: dict[str, str], + monkeypatch: pytest.MonkeyPatch, + engine: str = "python", ) -> SemanticInputs: - """Compile with the Python engine and keep the semantic completion stage's inputs.""" + """Compile with `engine` and keep the semantic completion stage's inputs.""" for relative_path, contents in files.items(): path: Path = project_dir / relative_path @@ -188,7 +198,7 @@ def capture(**arguments: Any) -> CompiledProject: return complete_semantic_diagnostics(**arguments) with monkeypatch.context() as patch: - patch.setenv(COMPILER_ENGINE_ENV_VAR, "python") + patch.setenv(COMPILER_ENGINE_ENV_VAR, engine) patch.setattr(assembly_project, "complete_semantic_diagnostics", capture) _ = build_project_graph( discovered_inputs=discover_project_inputs(project_dir=project_dir), @@ -248,9 +258,51 @@ def native_completion(inputs: SemanticInputs) -> CompiledProject | None: profile=inputs.profile, binding_results=inputs.binding_results, resource_sql_analysis=inputs.resource_sql_analysis, + session=inputs.native_session, ) +def session_corpus_files(*, corpus: str, rng: random.Random, model_count: int) -> dict[str, str]: + """One generated project from the failing-semantics or the analysis-session corpus.""" + + generators: dict[str, Callable[[], dict[str, str]]] = { + "semantic": lambda: generated_semantic_files( + rng=rng, model_count=model_count, require_analysis=False + ), + "analysis": lambda: generated_analysis_files(rng=rng, model_count=model_count), + } + return generators[corpus]() + + +def proven_output_count(project: CompiledProject) -> int: + """How many models a dynamic pivot proof gave their output names.""" + + return sum( + model.dynamic_column_contract is not None and model.dynamic_column_contract.output_proven + for model in project.models + ) + + +def without_session(inputs: SemanticInputs) -> SemanticInputs: + """The same stage inputs with every model's output names and lineage in the payload.""" + + return replace(inputs, native_session=None) + + +def record_session_models(*, monkeypatch: pytest.MonkeyPatch) -> list[frozenset[str]]: + """Keep each completion's models whose output names and lineage the session supplies.""" + + selections: list[frozenset[str]] = [] + + def recorded(**arguments: Any) -> frozenset[str]: + selected: frozenset[str] = session_fact_models(**arguments) + selections.append(selected) + return selected + + monkeypatch.setattr(semantic_stage, "session_fact_models", recorded) + return selections + + def completion_view(project: CompiledProject) -> tuple[object, ...]: """Everything the stage decides: diagnostics and each model's binding and type facts.""" diff --git a/tests/integration/src/sqlbuild/compiler/semantic_checks/test_native_semantic_checks.py b/tests/integration/src/sqlbuild/compiler/semantic_checks/test_native_semantic_checks.py index 96d98e0bbb..49e1f01f6c 100644 --- a/tests/integration/src/sqlbuild/compiler/semantic_checks/test_native_semantic_checks.py +++ b/tests/integration/src/sqlbuild/compiler/semantic_checks/test_native_semantic_checks.py @@ -14,6 +14,7 @@ from tests.integration.src.sqlbuild.compiler.semantic_checks._test_types import ( DeferredSemanticTestCase, GeneratedSemanticParityTestCase, + SessionCompletionTestCase, ) from tests.integration.src.sqlbuild.compiler.semantic_checks.helpers import ( SemanticInputs, @@ -24,9 +25,13 @@ generated_semantic_files, native_completion, note_kinds, + proven_output_count, python_completion, record_native_statuses, + record_session_models, + session_corpus_files, with_dialect, + without_session, ) _NOTE_KINDS: tuple[str, ...] = ("downstream output uses", "downstream uses of", " has: ") @@ -154,5 +159,83 @@ def test_given_deferred_projects_when_completing_then_python_completes_and_recor assert deferral_records(record_dir) == test_case.expected_kinds +@pytest.mark.parametrize( + "test_case", + [ + SessionCompletionTestCase( + description="failing semantics corpus", + corpus="semantic", + seed=20261010, + count=6, + model_count=12, + expected_session_models=44, + expected_payload_models=28, + expected_proven_outputs=0, + expected_minimum_codes={"B002": 1, "downstream output uses": 1}, + ), + SessionCompletionTestCase( + description="analysis session corpus with pivots, stars and set operations", + corpus="analysis", + seed=20261011, + count=4, + model_count=16, + expected_session_models=68, + expected_payload_models=28, + expected_proven_outputs=10, + expected_minimum_codes={"B002": 1}, + ), + ], + ids=lambda case: case.description, +) +def test_given_preview_compiles_when_completing_from_the_session_then_matches_payload_and_python( + test_case: SessionCompletionTestCase, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + rng: random.Random = random.Random(test_case.seed) + captured: list[SemanticInputs] = [ + captured_semantic_inputs( + project_dir=tmp_path / f"project_{index}", + files=session_corpus_files( + corpus=test_case.corpus, rng=rng, model_count=test_case.model_count + ), + monkeypatch=monkeypatch, + engine="native-preview", + ) + for index in range(test_case.count) + ] + selections: list[frozenset[str]] = record_session_models(monkeypatch=monkeypatch) + codes: Counter[str] = Counter() + python_views: list[tuple[object, ...]] = [] + payload_views: list[tuple[object, ...]] = [] + session_views: list[tuple[object, ...]] = [] + for inputs in captured: + python: CompiledProject = python_completion(inputs=inputs, monkeypatch=monkeypatch) + codes.update(item.code for item in python.diagnostics) + codes.update(note_kinds(python, _NOTE_KINDS)) + python_views.append(completion_view(python)) + payload_views.append(completion_view(completed_natively(without_session(inputs)))) + session_views.append(completion_view(completed_natively(inputs))) + session_models: int = sum(len(selected) for selected in selections) + model_count: int = sum(len(inputs.project.models) for inputs in captured) + + assert all(inputs.native_session is not None for inputs in captured) + assert session_views == python_views + assert payload_views == python_views + assert ( + session_models, + model_count - session_models, + sum(proven_output_count(inputs.project) for inputs in captured), + ) == ( + test_case.expected_session_models, + test_case.expected_payload_models, + test_case.expected_proven_outputs, + ) + assert { + code: min(codes[code], minimum) + for code, minimum in test_case.expected_minimum_codes.items() + } == test_case.expected_minimum_codes + + if __name__ == "__main__": pytest.main([__file__, "-vv"]) diff --git a/tests/integration/src/sqlbuild/compiler/sql_test_glue/_test_types.py b/tests/integration/src/sqlbuild/compiler/sql_test_glue/_test_types.py index 1ead44a814..f4abf5a7a3 100644 --- a/tests/integration/src/sqlbuild/compiler/sql_test_glue/_test_types.py +++ b/tests/integration/src/sqlbuild/compiler/sql_test_glue/_test_types.py @@ -22,3 +22,15 @@ class GeneratedSqlTestPlanningParityTestCase: expected_native_raised_kinds: frozenset[str] expected_minimum_answered_batches: int expected_minimum_raised_outcomes: int + + +@dataclass(frozen=True) +class GeneratedSqlTestAssemblyParityTestCase: + """Seeded SQL-test projects native and Python assembly must compile identically.""" + + description: str + seed: int + count: int + test_count: int + shape: SqlTestCorpusShape + expected_native_assemblies: dict[str, int] diff --git a/tests/integration/src/sqlbuild/compiler/sql_test_glue/helpers.py b/tests/integration/src/sqlbuild/compiler/sql_test_glue/helpers.py index cfbadc548b..8cc9dbc032 100644 --- a/tests/integration/src/sqlbuild/compiler/sql_test_glue/helpers.py +++ b/tests/integration/src/sqlbuild/compiler/sql_test_glue/helpers.py @@ -15,10 +15,12 @@ import sqlbuild._native as native_module from sqlbuild.adapter.contract.classes.base_adapter import BaseAdapter from sqlbuild.adapters.duckdb.classes.duckdb_adapter import DuckDbAdapter +from sqlbuild.compiler.compile._helpers.native_stages import sql_tests as sql_test_stage from sqlbuild.compiler.compile.models import ( CompiledModelSqlTestPayload, CompiledProject, CompiledSqlTest, + CompileProjectInputs, CompileSqlTestCte, ) from sqlbuild.compiler.discovery.main.discover import discover_project_inputs @@ -27,10 +29,15 @@ from sqlbuild.compiler.planner._helpers.sql_tests import native_planning from sqlbuild.compiler.planner.models import NativeSqlTestArtifact from sqlbuild.compiler.sql_test_glue.models import ( + NativeSqlTestAssembly, + NativeSqlTestAssemblyRequest, NativeSqlTestChainRequest, NativeSqlTestPlanningRequest, ) -from sqlbuild.compiler.sql_test_glue.types import NativeSqlTestPlanRow +from sqlbuild.compiler.sql_test_glue.types import ( + NativeSqlTestAssemblyRow, + NativeSqlTestPlanRow, +) @dataclass(frozen=True) @@ -284,13 +291,121 @@ def _model_test(*, rng: random.Random, index: int, shape: SqlTestCorpusShape) -> return f'TEST (name "generated_{index}"{window});\n\nWITH\n{body}\nSELECT 1\n' -def compiled_project(*, project_dir: Path, files: dict[str, str]) -> CompiledProject: - """Write and compile a project, keeping any compile diagnostics on it.""" +_CASE_VALUES: dict[str, tuple[str, ...]] = { + "string": ('"open"', '"O\\\'Brien"', '"caf\u00e9 \u2603"', '""', '"a\\\\b"', "null"), + "integer": ("0", "-7", "8", "9223372036854775807", "null"), + "boolean": ("true", "false", "null"), + "float": ("1.25", "-0.5", "0.1", "100.0", "0.0", "null"), + "decimal": ( + '"2.4700"', + '"-0.000"', + '"3.00"', + '"1E+5"', + '"0.0001230"', + '"12345678901234567890123456789.5"', + "null", + ), +} +_REFERENCING_HELPERS: tuple[str, ...] = ( + 'SELECT order_id, amount FROM __source("raw_orders")', + 'SELECT order_id, amount FROM __ref("stg_orders")', + 'SELECT region, label FROM __seed("regions")', + 'SELECT order_id, amount FROM __table_fn("table_fn__customer_orders")(1)', + "SELECT 1 AS order_id, 2 AS amount", +) +_MOCK_READS: tuple[str, ...] = ( + "SELECT * FROM {helper}", + "SELECT * FROM {upper_helper}", + "SELECT * FROM {via}", + "WITH {helper} AS (SELECT 1 AS order_id) SELECT * FROM {helper}", + "SELECT * FROM main.{helper}", + "SELECT * FROM {helper} WHERE order_id ==> 1", + "SELECT 1 AS order_id", +) +_ASSEMBLY_TARGETS: tuple[str, ...] = ("stg_orders", "int_orders", "fct_regions") + + +def generated_sql_test_assembly_files( + *, rng: random.Random, test_count: int, shape: SqlTestCorpusShape +) -> dict[str, str]: + """The planning projects plus typed parameter cases and mocks reading referencing helpers.""" + + files: dict[str, str] = generated_sql_test_files(rng=rng, test_count=test_count, shape=shape) + files.update( + (f"tests/unit/test_cases_{index}.sql", _case_test(rng=rng, index=index)) + for index in range(test_count) + ) + files.update( + (f"tests/unit/test_helper_mock_{index}.sql", _helper_mock_test(rng=rng, index=index)) + for index in range(test_count) + ) + return files + + +def _case_test(*, rng: random.Random, index: int) -> str: + """A parameterized test over random typed parameters and up to three random cases.""" + + kinds: list[str] = rng.sample(sorted(_CASE_VALUES), k=rng.randint(1, 3)) + parameters: str = ", ".join(f"p_{kind} (type {kind}, nullable true)" for kind in kinds) + cases: str = ", ".join( + f"case_{case} ({_case_values(rng=rng, kinds=kinds)})" for case in range(rng.randint(1, 3)) + ) + target: str = rng.choice(_ASSEMBLY_TARGETS) + used: str = ", ".join(f'@param("p_{kind}") AS p_{kind}' for kind in kinds) + return ( + f'TEST (name "cases_{index}", parameters ({parameters}), cases ({cases}));\n\n' + f"WITH\n{_UPSTREAM[target][0]} AS (SELECT 1 AS order_id, {used}),\n" + f'__assert__{target}_rows AS (SELECT * FROM __ref("{target}") WHERE 1 = 0)\nSELECT 1\n' + ) + + +def _case_values(*, rng: random.Random, kinds: list[str]) -> str: + return ", ".join(f"p_{kind} {rng.choice(_CASE_VALUES[kind])}" for kind in kinds) + + +def _helper_mock_test(*, rng: random.Random, index: int) -> str: + """A model test whose mocks read helpers, some of which call a reference.""" + + helper: str = f"source_rows_{index}" + via: str = f"via_{index}" + target: str = rng.choice(_ASSEMBLY_TARGETS) + mocks: list[str] = rng.sample(list(_UPSTREAM[target]), k=rng.randint(1, len(_UPSTREAM[target]))) + reads: dict[str, str] = {"helper": helper, "upper_helper": helper.upper(), "via": via} + mock_ctes: list[str] = [ + f"{mock} AS (\n {rng.choice(_MOCK_READS).format(**reads)}\n)" for mock in mocks + ] + check: str = rng.choice( + ( + f"__expected__{target} AS (SELECT order_id FROM {helper})", + f'__assert__{target}_rows AS (SELECT * FROM __ref("{target}") WHERE 1 = 0)', + f"__expected__{target} AS (SELECT 1 AS order_id)", + ) + ) + comment: str = rng.choice(("", "", "-- r\u00e9sum\u00e9\n")) + ctes: str = ",\n".join( + ( + f"{helper} AS (\n {rng.choice(_REFERENCING_HELPERS)}\n)", + f"{via} AS (SELECT * FROM {helper})", + *mock_ctes, + check, + ) + ) + return f'TEST (name "helper_mock_{index}");\n\nWITH\n{comment}{ctes}\nSELECT 1\n' + + +def write_project(*, project_dir: Path, files: dict[str, str]) -> None: + """Write a project's files below `project_dir`.""" for relative_path, contents in files.items(): path: Path = project_dir / relative_path path.parent.mkdir(parents=True, exist_ok=True) _ = path.write_text(contents, encoding="utf-8") + + +def compiled_project(*, project_dir: Path, files: dict[str, str]) -> CompiledProject: + """Write and compile a project, keeping any compile diagnostics on it.""" + + write_project(project_dir=project_dir, files=files) return build_project_graph( discovered_inputs=discover_project_inputs(project_dir=project_dir), adapter=DuckDbAdapter(), @@ -330,6 +445,65 @@ def use_sql_test_glue(*, monkeypatch: pytest.MonkeyPatch, enabled: bool) -> None ) +def assembly_outcome( + *, project_dir: Path, monkeypatch: pytest.MonkeyPatch, native: bool +) -> PlanningCallOutcome: + """The compiled SQL tests and diagnostics with native or Python assembly, or what it raises.""" + + monkeypatch.setattr( + sql_test_stage, + "native_stage_enabled", + lambda stage: native and stage is NativeStage.SQL_TEST_GLUE, + ) + return _outcome(lambda: _compiled_tests_and_diagnostics(project_dir=project_dir)) + + +def _compiled_tests_and_diagnostics(*, project_dir: Path) -> tuple[object, object]: + project: CompiledProject = build_project_graph( + discovered_inputs=discover_project_inputs(project_dir=project_dir), + adapter=DuckDbAdapter(), + ).project + return project.sql_tests, project.diagnostics + + +def record_native_assemblies(*, monkeypatch: pytest.MonkeyPatch) -> Counter[str]: + """Count tests compile takes from the native assembly, with diagnostics, cases, or defers. + + `native_assembled` counts only assemblies the stage seam hands compile; a deferred test + counts under `deferred_` and is assembled by Python, so it never counts as native work. + """ + + answers: Counter[str] = Counter() + assemble: Callable[[NativeSqlTestAssemblyRequest], list[NativeSqlTestAssemblyRow]] = ( + native_module.assemble_compiled_sql_tests + ) + seam: Callable[..., tuple[NativeSqlTestAssembly | None, ...]] = ( + sql_test_stage.assemble_native_sql_tests + ) + + def counted_deferrals(request: NativeSqlTestAssemblyRequest) -> list[NativeSqlTestAssemblyRow]: + rows: list[NativeSqlTestAssemblyRow] = assemble(request) + deferrals: list[str] = list(filter(None, (row[1] for row in rows))) + answers.update(f"deferred_{kind}" for kind in deferrals) + return rows + + def counted_assemblies( + *, inputs: CompileProjectInputs + ) -> tuple[NativeSqlTestAssembly | None, ...]: + assemblies: tuple[NativeSqlTestAssembly | None, ...] = seam(inputs=inputs) + native: list[NativeSqlTestAssembly] = list(filter(None, assemblies)) + answers["native_assembled"] += len(native) + answers["native_with_diagnostics"] += sum(bool(item.diagnostics) for item in native) + answers["native_case_fingerprints"] += sum( + item.test.case_fingerprint is not None for item in native + ) + return assemblies + + monkeypatch.setattr(native_module, "assemble_compiled_sql_tests", counted_deferrals) + monkeypatch.setattr(sql_test_stage, "assemble_native_sql_tests", counted_assemblies) + return answers + + def planning_outcome( *, project: CompiledProject, diff --git a/tests/integration/src/sqlbuild/compiler/sql_test_glue/test_native_sql_test_planning_glue.py b/tests/integration/src/sqlbuild/compiler/sql_test_glue/test_native_sql_test_planning_glue.py index c24cf34efd..22cc63e2ea 100644 --- a/tests/integration/src/sqlbuild/compiler/sql_test_glue/test_native_sql_test_planning_glue.py +++ b/tests/integration/src/sqlbuild/compiler/sql_test_glue/test_native_sql_test_planning_glue.py @@ -1,4 +1,4 @@ -"""SQL tests planned natively from compiled objects equal the JSON-request plans, test by test.""" +"""SQL tests assembled and planned natively equal Python's assembly and the JSON-request plans.""" from __future__ import annotations @@ -17,6 +17,7 @@ from sqlbuild.compiler.compile.models import CompiledProject, CompiledSqlTest from tests.integration.src.sqlbuild.compiler.helpers import mismatches from tests.integration.src.sqlbuild.compiler.sql_test_glue._test_types import ( + GeneratedSqlTestAssemblyParityTestCase, GeneratedSqlTestPlanningParityTestCase, ) from tests.integration.src.sqlbuild.compiler.sql_test_glue.helpers import ( @@ -26,15 +27,19 @@ PlanningCallOutcome, SqlTestCorpusShape, artifact_outcome, + assembly_outcome, chain_outcome, compiled_project, + generated_sql_test_assembly_files, generated_sql_test_files, native_raised_kinds, outcome_kind, planning_outcome, record_native_answers, + record_native_assemblies, use_sql_test_glue, with_unmocked_assertion, + write_project, ) _ADAPTERS: dict[str, BaseAdapter] = { @@ -171,3 +176,62 @@ def test_given_generated_sql_tests_when_planning_natively_then_plans_match_the_j outcomes["batch_answered"] >= test_case.expected_minimum_answered_batches, outcomes["raised"] >= test_case.expected_minimum_raised_outcomes, ) == ([], True, True, True, True, True, True, True), (native_answers, outcomes) + + +@pytest.mark.parametrize( + "test_case", + [ + GeneratedSqlTestAssemblyParityTestCase( + description="model, direct, parameterized and mock-reads-helper tests", + seed=20261010, + count=4, + test_count=12, + shape=SqlTestCorpusShape( + windows=(NO_WINDOW, VALID_WINDOW, INVERTED_WINDOW), + stray_window_share=0.1, + helper_redefinition_share=0.15, + assertion_share=0.2, + unflattenable_assertion_share=0.1, + ), + expected_native_assemblies={ + "native_assembled": 181, + "native_with_diagnostics": 17, + "native_case_fingerprints": 96, + "deferred_macro_mocks": 4, + "deferred_non_ascii_text": 11, + "deferred_decimal_context": 5, + }, + ) + ], + ids=lambda case: case.description, +) +def test_given_generated_sql_tests_when_assembling_natively_then_compiled_tests_match_python( + test_case: GeneratedSqlTestAssemblyParityTestCase, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +) -> None: + rng: random.Random = random.Random(test_case.seed) + native_assemblies: Counter[str] = record_native_assemblies(monkeypatch=monkeypatch) + differences: list[tuple[object, object, object]] = [] + outcomes: Counter[str] = Counter() + for index in range(test_case.count): + project_dir: Path = tmp_path / f"project_{index}" + write_project( + project_dir=project_dir, + files=generated_sql_test_assembly_files( + rng=rng, test_count=test_case.test_count, shape=test_case.shape + ), + ) + expected: PlanningCallOutcome = assembly_outcome( + project_dir=project_dir, monkeypatch=monkeypatch, native=False + ) + actual: PlanningCallOutcome = assembly_outcome( + project_dir=project_dir, monkeypatch=monkeypatch, native=True + ) + differences.extend(mismatches(inputs=[index], expected=[expected], actual=[actual])) + outcomes[outcome_kind(actual)] += 1 + + assert (differences, dict(native_assemblies)) == ( + [], + test_case.expected_native_assemblies, + ), outcomes diff --git a/tests/unit/scripts/compile_performance_ratio/_helpers/_test_types.py b/tests/unit/scripts/compile_performance_ratio/_helpers/_test_types.py index 459d0a388b..5f2afdd6ce 100644 --- a/tests/unit/scripts/compile_performance_ratio/_helpers/_test_types.py +++ b/tests/unit/scripts/compile_performance_ratio/_helpers/_test_types.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, field -from scripts.compile_performance_ratio.models import CompileComparison +from scripts.compile_performance_ratio.models import CompileComparison, CompileRun @dataclass(frozen=True) @@ -37,3 +37,10 @@ class OneModelEditErrorTestCase: description: str model_files: dict[str, str] expected_message: str + + +@dataclass(frozen=True) +class MedianPhasesTestCase: + description: str + runs: tuple[CompileRun, ...] + expected_phases: dict[str, float] diff --git a/tests/unit/scripts/compile_performance_ratio/_helpers/test_measure.py b/tests/unit/scripts/compile_performance_ratio/_helpers/test_measure.py new file mode 100644 index 0000000000..cc7cff4c35 --- /dev/null +++ b/tests/unit/scripts/compile_performance_ratio/_helpers/test_measure.py @@ -0,0 +1,58 @@ +"""Tests for per-phase medians in the same-runner compile performance ratio guard.""" + +import pytest + +from scripts.compile_performance_ratio._helpers.measure import median_phases +from scripts.compile_performance_ratio.models import CompileRun +from tests.unit.scripts.compile_performance_ratio._helpers._test_types import ( + MedianPhasesTestCase, +) + + +@pytest.mark.parametrize( + "test_case", + ( + MedianPhasesTestCase( + description="a phase every run reports gets its median", + runs=( + CompileRun( + label="head", + wall_seconds=1.0, + cpu_seconds=1.0, + timings_ms={"contracts_cpu_ms": 90}, + ), + CompileRun( + label="head", + wall_seconds=1.0, + cpu_seconds=1.0, + timings_ms={"contracts_cpu_ms": 120}, + ), + CompileRun( + label="head", + wall_seconds=1.0, + cpu_seconds=1.0, + timings_ms={"contracts_cpu_ms": 100}, + ), + ), + expected_phases={"contracts_cpu_ms": 100}, + ), + MedianPhasesTestCase( + description="a phase one run omits is left unreported instead of counted as zero", + runs=( + CompileRun( + label="head", + wall_seconds=1.0, + cpu_seconds=1.0, + timings_ms={"contracts_cpu_ms": 90}, + ), + CompileRun(label="head", wall_seconds=1.0, cpu_seconds=1.0, timings_ms={}), + ), + expected_phases={}, + ), + ), + ids=lambda case: case.description, +) +def test_given_compile_runs_when_taking_phase_medians_then_reports_only_complete_phases( + test_case: MedianPhasesTestCase, +) -> None: + assert median_phases(runs=list(test_case.runs)) == test_case.expected_phases diff --git a/tests/unit/scripts/compiler_differential/_helpers/goldens/__init__.py b/tests/unit/scripts/compiler_differential/_helpers/goldens/__init__.py new file mode 100644 index 0000000000..c18b17ecc8 --- /dev/null +++ b/tests/unit/scripts/compiler_differential/_helpers/goldens/__init__.py @@ -0,0 +1 @@ +"""Unit tests for the golden compile outputs.""" diff --git a/tests/unit/scripts/compiler_differential/_helpers/goldens/_test_types.py b/tests/unit/scripts/compiler_differential/_helpers/goldens/_test_types.py new file mode 100644 index 0000000000..7f20ecb41a --- /dev/null +++ b/tests/unit/scripts/compiler_differential/_helpers/goldens/_test_types.py @@ -0,0 +1,39 @@ +"""Test case types for the golden compile outputs.""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path + +from scripts.compiler_differential.models import EngineRun + + +@dataclass(frozen=True) +class GoldenPathTestCase: + """A corpus project name and where its golden lives, if anywhere.""" + + description: str + project: str + expected_path: Path | None + + +@dataclass(frozen=True) +class GoldenPayloadTestCase: + """One engine run and the masked golden it must produce.""" + + description: str + run: EngineRun + masked_paths: tuple[tuple[str, str], ...] + expected_payload: dict[str, object] + + +@dataclass(frozen=True) +class GoldenCheckTestCase: + """A recorded golden, the runs checked against it, and the differences reported.""" + + description: str + project: str + recorded: tuple[EngineRun, ...] + checked: tuple[EngineRun, ...] + expected_differences: tuple[tuple[str, tuple[str, str] | None], ...] + seed_range_dir: str = "" diff --git a/tests/unit/scripts/compiler_differential/_helpers/goldens/helpers.py b/tests/unit/scripts/compiler_differential/_helpers/goldens/helpers.py new file mode 100644 index 0000000000..a4eca5e4ff --- /dev/null +++ b/tests/unit/scripts/compiler_differential/_helpers/goldens/helpers.py @@ -0,0 +1,46 @@ +"""Engine runs for the golden output tests.""" + +from __future__ import annotations + +import json + +from scripts.compiler_differential.models import CommandOutcome, EngineRun + +PROJECT_PATH: str = "/work/failure__unknown-ref/project" + + +def engine_run(*, engine: str, message: str, compiled_sql: str) -> EngineRun: + """A one-command run whose first diagnostic carries `message` and one compiled model.""" + + report: dict[str, object] = { + "compile_timings": {"total": 1.5}, + "diagnostics": [{"code": "P001", "message": message, "severity": "error"}], + } + return EngineRun( + engine=engine, + outcomes=( + CommandOutcome( + label="compile", exit_code=1, stdout=json.dumps(report), stderr="done in 12ms\n" + ), + ), + compiled={"marts/customer_totals.sql": compiled_sql.encode("utf-8")}, + manifest=json.dumps( + { + "metadata": {"generated_at": "now"}, + "child_map": {}, + "nodes": { + "model.orders.customer_totals": { + "name": "customer_totals", + "compiled_code": compiled_sql, + "raw_code": "SELECT 1", + "checksum": {"checksum": "abc"}, + "config": {"materialized": "table"}, + } + }, + "sources": {}, + "macros": {}, + "parent_map": {"model.orders.customer_totals": []}, + } + ), + dag=None, + ) diff --git a/tests/unit/scripts/compiler_differential/_helpers/goldens/test_compiler_goldens.py b/tests/unit/scripts/compiler_differential/_helpers/goldens/test_compiler_goldens.py new file mode 100644 index 0000000000..44e1fc9f37 --- /dev/null +++ b/tests/unit/scripts/compiler_differential/_helpers/goldens/test_compiler_goldens.py @@ -0,0 +1,214 @@ +"""Golden compile outputs are masked, located per corpus project, checked and rewritten.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from scripts.compiler_differential._helpers.goldens.goldens import ( + golden_differences, + golden_path, + golden_payload, + write_golden_seed_range, +) +from scripts.compiler_differential.models import CorpusProject, Difference, ExpectedOutcome +from tests.unit.scripts.compiler_differential._helpers.goldens._test_types import ( + GoldenCheckTestCase, + GoldenPathTestCase, + GoldenPayloadTestCase, +) +from tests.unit.scripts.compiler_differential._helpers.goldens.helpers import ( + PROJECT_PATH, + engine_run, +) + +_SQL: str = "SELECT customer_id\nFROM orders -- 20261009T010203Z_0123456789ab\n" +_MESSAGE: str = f"model references unknown model 'ghost' in '{PROJECT_PATH}/models/a.sql'" + + +@pytest.mark.parametrize( + "test_case", + [ + GoldenPathTestCase( + description="seed", project="seed/3", expected_path=Path("goldens/seed/3.json") + ), + GoldenPathTestCase( + description="dialect_seed", + project="seed/0-snowflake", + expected_path=Path("goldens/seed/0-snowflake.json"), + ), + GoldenPathTestCase( + description="failure_case", + project="failure/unknown-ref", + expected_path=Path("goldens/failure/unknown-ref.json"), + ), + GoldenPathTestCase(description="dense_has_none", project="dense/3000", expected_path=None), + ], + ids=lambda case: case.description, +) +def test_given_corpus_project_when_locating_its_golden_then_only_golden_corpora_have_one( + test_case: GoldenPathTestCase, +) -> None: + path: Path | None = golden_path(golden_dir=Path("goldens"), project=test_case.project) + + assert path == test_case.expected_path + + +@pytest.mark.parametrize( + "test_case", + [ + GoldenPayloadTestCase( + description="paths_ids_timings_and_repeated_sql_masked", + run=engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL), + masked_paths=((PROJECT_PATH, ""),), + expected_payload={ + "commands": [ + { + "label": "compile", + "exit_code": 1, + "diagnostics": [ + { + "code": "P001", + "message": ( + "model references unknown model 'ghost' in " + "'/models/a.sql'" + ), + "severity": "error", + } + ], + } + ], + "compiled": { + "marts/customer_totals.sql": [ + "SELECT customer_id", + "FROM orders -- ", + "", + ] + }, + "manifest": { + "nodes": { + "model.orders.customer_totals": { + "name": "customer_totals", + "config": {"materialized": "table"}, + } + }, + "sources": {}, + "macros": {}, + "parent_map": {"model.orders.customer_totals": []}, + }, + }, + ) + ], + ids=lambda case: case.description, +) +def test_given_engine_run_when_building_golden_then_run_specific_noise_is_masked( + test_case: GoldenPayloadTestCase, +) -> None: + payload: dict[str, object] = golden_payload( + run=test_case.run, masked_paths=test_case.masked_paths + ) + + assert payload == test_case.expected_payload + + +@pytest.mark.parametrize( + "test_case", + [ + GoldenCheckTestCase( + description="identical_engines_match", + project="failure/unknown-ref", + recorded=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + checked=( + engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL), + engine_run(engine="native", message=_MESSAGE, compiled_sql=_SQL), + ), + expected_differences=(), + ), + GoldenCheckTestCase( + description="changed_sql_names_the_engine", + project="failure/unknown-ref", + recorded=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + checked=( + engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL), + engine_run(engine="native", message=_MESSAGE, compiled_sql="SELECT 2\n"), + ), + expected_differences=(("golden (native)", ("golden", "native")),), + ), + GoldenCheckTestCase( + description="missing_failure_golden_fails", + project="failure/unknown-ref", + recorded=(), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(("golden unknown-ref.json", ("golden", "hint")),), + ), + GoldenCheckTestCase( + description="missing_seed_golden_outside_the_recorded_range_is_skipped", + project="seed/40", + recorded=(), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(), + ), + GoldenCheckTestCase( + description="missing_seed_golden_inside_the_recorded_range_fails", + project="seed/3", + recorded=(), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(("golden 3.json", ("golden", "hint")),), + ), + GoldenCheckTestCase( + description="missing_dialect_variant_of_the_recorded_first_seed_fails", + project="seed/0-postgres", + recorded=(), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(("golden 0-postgres.json", ("golden", "hint")),), + ), + GoldenCheckTestCase( + description="dialect_variant_of_an_ad_hoc_first_seed_is_skipped", + project="seed/3-postgres", + recorded=(), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(), + ), + GoldenCheckTestCase( + description="missing_seed_range_fails_closed_even_with_the_seed_golden", + project="seed/3", + recorded=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + checked=(engine_run(engine="python", message=_MESSAGE, compiled_sql=_SQL),), + expected_differences=(("golden seed_range.toml", ("golden", "hint")),), + seed_range_dir="elsewhere", + ), + ], + ids=lambda case: case.description, +) +def test_given_recorded_golden_when_checking_runs_then_each_differing_engine_is_reported( + test_case: GoldenCheckTestCase, tmp_path: Path +) -> None: + project: CorpusProject = CorpusProject( + name=test_case.project, commands=(), expected=ExpectedOutcome() + ) + write_golden_seed_range(golden_dir=tmp_path / test_case.seed_range_dir, seed_start=0, seeds=12) + for recorded in test_case.recorded: + _ = golden_differences( + project=project, + runs=(recorded,), + golden_dir=tmp_path, + mode="update", + masked_paths=((PROJECT_PATH, ""),), + ) + + differences: list[Difference] = golden_differences( + project=project, + runs=test_case.checked, + golden_dir=tmp_path, + mode="check", + masked_paths=((PROJECT_PATH, ""),), + ) + + assert [(difference.artifact, difference.labels) for difference in differences] == list( + test_case.expected_differences + ) + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/unit/scripts/compiler_differential/_helpers/running/_test_types.py b/tests/unit/scripts/compiler_differential/_helpers/running/_test_types.py index f9054ef85e..3384925a54 100644 --- a/tests/unit/scripts/compiler_differential/_helpers/running/_test_types.py +++ b/tests/unit/scripts/compiler_differential/_helpers/running/_test_types.py @@ -5,7 +5,12 @@ from collections.abc import Callable from dataclasses import dataclass -from scripts.compiler_differential.models import ExpectedOutcome, ProjectComparison +from scripts.compiler_differential.models import ( + AnalysisRecords, + ExpectedOutcome, + ProjectComparison, + RecordedRun, +) @dataclass(frozen=True) @@ -62,6 +67,7 @@ class SummaryTestCase: description: str comparisons: list[ProjectComparison] missing_coverage: dict[str, tuple[str, ...]] + gate_failures: tuple[str, ...] expected_lines: tuple[str, ...] expected_absent: tuple[str, ...] @@ -74,6 +80,7 @@ class AnalysisRecordsTestCase: files: dict[str, str] expected_wheel_sites: dict[tuple[str, str], int] expected_deferrals: dict[tuple[str, str], int] + expected_fallbacks: dict[tuple[str, str], int] expected_lines: tuple[str, ...] @@ -85,3 +92,35 @@ class FailureEvidenceTestCase: stderr_by_engine: dict[str, str] expected_files: tuple[str, ...] expected_evidence_engines: tuple[str, ...] + + +@dataclass(frozen=True) +class FallbackGateTestCase: + """An allow-list file, what one run observed, and the problems the gate must report.""" + + description: str + allow_list: str + observed: dict[tuple[str, str, str, str], dict[str, int]] + run: RecordedRun + expected_problems: list[str] + + +@dataclass(frozen=True) +class FallbackRecordsTestCase: + """Per-engine records of one project and the allow-list entries they add up to.""" + + description: str + project: str + records: tuple[AnalysisRecords, AnalysisRecords] + expected_observed: dict[tuple[str, str, str, str], dict[str, int]] + + +@dataclass(frozen=True) +class FallbackRewriteTestCase: + """An allow-list, a run that rewrites it, and the counts the rewritten list must hold.""" + + description: str + allow_list: str + observed: dict[tuple[str, str, str, str], dict[str, int]] + run: RecordedRun + expected_counts: dict[tuple[str, str, str, str], dict[str, int]] diff --git a/tests/unit/scripts/compiler_differential/_helpers/running/test_native_fallbacks.py b/tests/unit/scripts/compiler_differential/_helpers/running/test_native_fallbacks.py new file mode 100644 index 0000000000..11ac5a0584 --- /dev/null +++ b/tests/unit/scripts/compiler_differential/_helpers/running/test_native_fallbacks.py @@ -0,0 +1,262 @@ +"""The fallback allow-list fails on new, changed and vanished entries and records new counts.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from scripts.compiler_differential._helpers.running.native_fallbacks import ( + fallback_problems, + observed_fallbacks, + read_allow_list, + write_allow_list, +) +from scripts.compiler_differential.models import ( + AllowList, + AnalysisRecords, + ProjectComparison, + RecordedRun, +) +from scripts.compiler_differential.types import FallbackKey +from tests.unit.scripts.compiler_differential._helpers.running._test_types import ( + FallbackGateTestCase, + FallbackRecordsTestCase, + FallbackRewriteTestCase, +) + +_VARIABLES: FallbackKey = ("native", "model_loop", "model_loop.sql_variables", "deferred") +_ANSWER: FallbackKey = ( + "native", + "reference_extraction", + "reference_extraction.native", + "reference_scans", +) +_ANSWER_ENTRY: str = ( + '\n[[entry]]\nengine = "native"\nstage = "reference_extraction"\n' + 'site = "reference_extraction.native"\nkind = "reference_scans"\n' +) +_LOOP_ANSWER: FallbackKey = ("native", "model_loop", "model_loop.native", "models") +_LOOP_VARIABLE_ANSWER: FallbackKey = ( + "native", + "model_loop", + "model_loop.native", + "sql_variables", +) +_LOOP_ANSWER_ENTRY: str = ( + '\n[[entry]]\nengine = "native"\nstage = "model_loop"\n' + 'site = "model_loop.native"\nkind = "models"\n' +) +_SESSION: FallbackKey = ("native-preview", "model_analysis", "analysis_session", "session") +_SHIPPED_RUN: RecordedRun = RecordedRun( + engines=("python", "native"), corpora=("seeds", "failures"), seed_start=0, seeds=12 +) +_LIST_HEAD: str = "seed_start = 0\nseeds = 12\n" +_VARIABLES_ENTRY: str = ( + '\n[[entry]]\nengine = "native"\nstage = "model_loop"\n' + 'site = "model_loop.sql_variables"\nkind = "deferred"\n' +) + + +@pytest.mark.parametrize( + "test_case", + [ + FallbackRecordsTestCase( + description="fallbacks_and_deferrals_keyed_by_engine_stage_site_kind", + project="seed/3", + records=( + AnalysisRecords(), + AnalysisRecords( + fallbacks={("model_loop.sql_variables", "deferred"): 2}, + deferrals={("session", "analysis_session"): 1}, + ), + ), + expected_observed={ + ("native-preview", "model_loop", "model_loop.sql_variables", "deferred"): { + "seed": 2 + }, + _SESSION: {"seed": 1}, + }, + ) + ], + ids=lambda case: case.description, +) +def test_given_engine_records_when_observing_then_entries_are_summed_per_corpus( + test_case: FallbackRecordsTestCase, +) -> None: + comparison: ProjectComparison = ProjectComparison( + project=test_case.project, differences=(), seconds=1.0, records=test_case.records + ) + + observed: dict[FallbackKey, dict[str, int]] = observed_fallbacks( + comparisons=[comparison], engines=("python", "native-preview") + ) + + assert observed == test_case.expected_observed + + +@pytest.mark.parametrize( + "test_case", + [ + FallbackGateTestCase( + description="exact_counts_pass", + allow_list=_LIST_HEAD + _VARIABLES_ENTRY + "counts = { failure = 3, seed = 195 }\n", + observed={_VARIABLES: {"failure": 3, "seed": 195}}, + run=_SHIPPED_RUN, + expected_problems=[], + ), + FallbackGateTestCase( + description="unlisted_entry_fails", + allow_list=_LIST_HEAD, + observed={_VARIABLES: {"seed": 195}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native model_loop model_loop.sql_variables deferred (seed): 195 not on the " + "allow-list; port it or list it with a reason" + ], + ), + FallbackGateTestCase( + description="vanished_entry_with_more_native_answers_fails_until_removed", + allow_list=_LIST_HEAD + + _VARIABLES_ENTRY + + "counts = { seed = 195 }\n" + + _LOOP_ANSWER_ENTRY + + "counts = { seed = 10 }\n", + observed={_LOOP_ANSWER: {"seed": 10}, _LOOP_VARIABLE_ANSWER: {"seed": 195}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native model_loop model_loop.native sql_variables (seed): native answered 195, " + "not on the allow-list; record it", + "native model_loop model_loop.sql_variables deferred (seed): listed but no " + "longer occurs; remove it from the allow-list", + ], + ), + FallbackGateTestCase( + description="vanished_entry_without_more_native_answers_means_the_stage_is_off", + allow_list=_LIST_HEAD + + _VARIABLES_ENTRY + + "counts = { seed = 195 }\n" + + _LOOP_ANSWER_ENTRY + + "counts = { seed = 10 }\n", + observed={_LOOP_ANSWER: {"seed": 10}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native model_loop model_loop.sql_variables deferred (seed): fallback disappeared " + "but native answers did not appear; the stage may be switched off. A port that " + "removes a fallback must report native answers for the work it now does" + ], + ), + FallbackGateTestCase( + description="changed_count_fails", + allow_list=_LIST_HEAD + _VARIABLES_ENTRY + "counts = { seed = 195 }\n", + observed={_VARIABLES: {"seed": 196}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native model_loop model_loop.sql_variables deferred (seed): 196 where the " + "allow-list expects 195; update the count" + ], + ), + FallbackGateTestCase( + description="upper_bound_allows_fewer_but_not_more", + allow_list=_LIST_HEAD + _VARIABLES_ENTRY + "max_counts = { failure = 5, seed = 200 }\n", + observed={_VARIABLES: {"failure": 6, "seed": 150}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native model_loop model_loop.sql_variables deferred (failure): 6 exceeds the " + "allowed 5" + ], + ), + FallbackGateTestCase( + description="engines_and_corpora_outside_the_run_are_not_checked", + allow_list=_LIST_HEAD + + _VARIABLES_ENTRY + + "counts = { fixture = 4, seed = 195 }\n" + + '\n[[entry]]\nengine = "native-preview"\nstage = "model_analysis"\n' + + 'site = "analysis_session"\nkind = "session"\ncounts = { seed = 1 }\n', + observed={_VARIABLES: {"seed": 195}}, + run=_SHIPPED_RUN, + expected_problems=[], + ), + FallbackGateTestCase( + description="vanished_native_answer_means_the_stage_runs_in_python", + allow_list=_LIST_HEAD + _ANSWER_ENTRY + "counts = { seed = 40 }\n", + observed={}, + run=_SHIPPED_RUN, + expected_problems=[ + "native reference_extraction reference_extraction.native reference_scans (seed): " + "native no longer answers here, so this work now runs in Python; restore the " + "native path, or record the change with a reason" + ], + ), + FallbackGateTestCase( + description="unlisted_native_answer_must_be_recorded", + allow_list=_LIST_HEAD, + observed={_ANSWER: {"seed": 40}}, + run=_SHIPPED_RUN, + expected_problems=[ + "native reference_extraction reference_extraction.native reference_scans (seed): " + "native answered 40, not on the allow-list; record it" + ], + ), + FallbackGateTestCase( + description="other_seed_range_is_refused", + allow_list=_LIST_HEAD, + observed={}, + run=RecordedRun( + engines=("python", "native"), corpora=("seeds",), seed_start=0, seeds=60 + ), + expected_problems=[ + "the allow-list holds counts for --seed-start 0 --seeds 12; this run used " + "--seed-start 0 --seeds 60" + ], + ), + ], + ids=lambda case: case.description, +) +def test_given_allow_list_when_checking_a_run_then_every_difference_is_a_problem( + test_case: FallbackGateTestCase, tmp_path: Path +) -> None: + path: Path = tmp_path / "native_fallbacks.toml" + _ = path.write_text(test_case.allow_list, encoding="utf-8") + + problems: list[str] = fallback_problems( + observed=test_case.observed, allowed=read_allow_list(path), run=test_case.run + ) + + assert problems == test_case.expected_problems + + +@pytest.mark.parametrize( + "test_case", + [ + FallbackRewriteTestCase( + description="other_engines_kept_and_the_run_recounted", + allow_list=_LIST_HEAD + + '\n[[entry]]\nengine = "native-preview"\nstage = "model_analysis"\n' + + 'site = "analysis_session"\nkind = "session"\ncounts = { seed = 1 }\n' + + _VARIABLES_ENTRY + + "counts = { seed = 9 }\n", + observed={_VARIABLES: {"failure": 3, "seed": 195}}, + run=_SHIPPED_RUN, + expected_counts={_SESSION: {"seed": 1}, _VARIABLES: {"failure": 3, "seed": 195}}, + ) + ], + ids=lambda case: case.description, +) +def test_given_recorded_run_when_rewriting_then_other_engines_are_kept_and_the_run_passes( + test_case: FallbackRewriteTestCase, tmp_path: Path +) -> None: + path: Path = tmp_path / "native_fallbacks.toml" + _ = path.write_text(test_case.allow_list, encoding="utf-8") + + write_allow_list(path=path, observed=test_case.observed, run=test_case.run) + + rewritten: AllowList = read_allow_list(path) + assert rewritten.counts == test_case.expected_counts + assert ( + fallback_problems(observed=test_case.observed, allowed=rewritten, run=test_case.run) == [] + ) + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"]) diff --git a/tests/unit/scripts/compiler_differential/_helpers/running/test_records.py b/tests/unit/scripts/compiler_differential/_helpers/running/test_records.py index 2f3a00bccd..ffac8427af 100644 --- a/tests/unit/scripts/compiler_differential/_helpers/running/test_records.py +++ b/tests/unit/scripts/compiler_differential/_helpers/running/test_records.py @@ -1,4 +1,4 @@ -"""Wheel-site and deferral records are summed per engine, site and corpus, never gated.""" +"""Wheel-site, deferral and fallback records are summed per engine, site and corpus.""" from __future__ import annotations @@ -33,16 +33,26 @@ "2-plan/analysis-deferrals-12.jsonl": ( json.dumps({"kind": "legacy_fallback", "site": "compact.py"}) + "\n" ), + "0-compile/native-fallbacks-11.json": json.dumps( + {"fallbacks": [["model_loop.sql_variables", "deferred", 2]]} + ), + "2-plan/native-fallbacks-12.json": json.dumps( + {"fallbacks": [["model_loop.sql_variables", "deferred", 1]]} + ), }, expected_wheel_sites={(_SITE, "parse_one"): 5}, expected_deferrals={("legacy_fallback", "compact.py"): 1}, + expected_fallbacks={("model_loop.sql_variables", "deferred"): 3}, expected_lines=( "Polyglot wheel calls (python):", f" 5 {_SITE} parse_one (seed 5)", "Analysis deferrals (python):", " 1 legacy_fallback compact.py (seed 1)", + "Native-to-Python fallbacks (python):", + " 3 model_loop.sql_variables deferred (seed 3)", "Polyglot wheel calls (native-preview): none recorded", "Analysis deferrals (native-preview): none recorded", + "Native-to-Python fallbacks (native-preview): none recorded", ), ) ], @@ -71,9 +81,10 @@ def test_given_record_files_when_reporting_then_counts_are_summed_per_engine_and ) ) - assert (records.wheel_sites, records.deferrals) == ( + assert (records.wheel_sites, records.deferrals, records.fallbacks) == ( test_case.expected_wheel_sites, test_case.expected_deferrals, + test_case.expected_fallbacks, ) assert report.splitlines() == list(test_case.expected_lines) diff --git a/tests/unit/scripts/compiler_differential/_helpers/running/test_report.py b/tests/unit/scripts/compiler_differential/_helpers/running/test_report.py index 16dc259015..cd1c3f8ee6 100644 --- a/tests/unit/scripts/compiler_differential/_helpers/running/test_report.py +++ b/tests/unit/scripts/compiler_differential/_helpers/running/test_report.py @@ -81,13 +81,15 @@ def test_given_covered_kinds_when_reporting_then_missing_kinds_are_named( description="identical_and_covered", comparisons=[_IDENTICAL], missing_coverage={"discovery": (), "render": ()}, + gate_failures=(), expected_lines=("Compiler differential passed: 1 projects identical",), - expected_absent=("FAILED",), + expected_absent=("FAILED", "make compiler-baselines"), ), SummaryTestCase( description="identical_but_coverage_missing", comparisons=[_IDENTICAL], missing_coverage={"discovery": ("providers", "crlf"), "render": ("path_default",)}, + gate_failures=(), expected_lines=( "Compiler differential FAILED: 0 of 1 projects differ", "Required discovery coverage missing: providers, crlf", @@ -99,11 +101,25 @@ def test_given_covered_kinds_when_reporting_then_missing_kinds_are_named( description="differences_and_coverage_missing", comparisons=[_IDENTICAL, _DIFFERING], missing_coverage={"discovery": ("providers",)}, + gate_failures=(), expected_lines=( "Compiler differential FAILED: 1 of 2 projects differ", "First difference: seed/1: `compile` stdout at /models/0", "Required discovery coverage missing: providers", ), + expected_absent=("passed", "make compiler-baselines"), + ), + SummaryTestCase( + description="gate_failure_says_how_to_record_intended_changes", + comparisons=[_IDENTICAL], + missing_coverage={}, + gate_failures=("native model_loop model_loop.native variable_substitutions (seed)",), + expected_lines=( + "Compiler differential FAILED: 0 of 1 projects differ", + "Native fallback allow-list: 1 problems (listed above)", + "Intended? Run `make compiler-baselines` and commit the changes to " + "scripts/compiler_differential/native_fallbacks.toml and tests/goldens/compiler", + ), expected_absent=("passed",), ), ], @@ -117,6 +133,7 @@ def test_given_results_and_coverage_when_summarizing_then_failures_never_read_as engines=("python", "native"), seconds=2.0, missing_coverage=test_case.missing_coverage, + gate_failures=test_case.gate_failures, ) assert all(line in summary for line in test_case.expected_lines), summary diff --git a/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_target_writer.py b/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_target_writer.py index 5ce8ab56c7..c851c21ef7 100644 --- a/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_target_writer.py +++ b/tests/unit/src/sqlbuild/cli/commands/main/compile/test_compile_target_writer.py @@ -341,6 +341,48 @@ def test_given_unchanged_test_artifact_when_writing_again_then_skips_test_plan_r assert planner_spy.call_count == test_case.expected_builder_calls +@pytest.mark.parametrize( + "test_case", + ( + TargetWriterCacheTestCase( + description="identical bytes with a moved mtime", expected_builder_calls=0 + ), + ), + ids=lambda case: case.description, +) +def test_given_artifact_with_moved_mtime_and_same_bytes_when_writing_then_reuses_it( + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + test_case: TargetWriterCacheTestCase, +) -> None: + target_dir: Path = tmp_path / "target" + project: CompiledProject = build_cached_target_writer_project(target_dir=target_dir) + _ = write_static_compile_target( + target_dir=target_dir, + adapter=DuckDbAdapter(), + project=project, + ) + artifact_path: Path = next((target_dir / "compiled" / "tests").rglob("*.sql")) + moved_mtime_ns: int = artifact_path.stat().st_mtime_ns + 1_000_000_000 + os.utime(artifact_path, ns=(moved_mtime_ns, moved_mtime_ns)) + planner_spy: Mock = Mock(wraps=target_writer_module.plan_and_render_sql_test_artifacts) + monkeypatch.setattr(target_writer_module, "plan_and_render_sql_test_artifacts", planner_spy) + + _ = write_static_compile_target( + target_dir=target_dir, + adapter=DuckDbAdapter(), + project=project, + ) + _ = write_static_compile_target( + target_dir=target_dir, + adapter=DuckDbAdapter(), + project=project, + ) + + assert planner_spy.call_count == test_case.expected_builder_calls + assert artifact_path.stat().st_mtime_ns == moved_mtime_ns + + @pytest.mark.parametrize( "test_case", ( diff --git a/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/_test_types.py b/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/_test_types.py index a49bf87317..6fd230b52e 100644 --- a/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/_test_types.py +++ b/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/_test_types.py @@ -10,6 +10,7 @@ class DynamicColumnContractDispatchTestCase: description: str sql_analysis: ModelSqlAnalysis | None + native_proof: DynamicColumnContractProof | None dialect: str families: tuple[SchemaDynamicColumnFamily, ...] expected_proof: DynamicColumnContractProof | None diff --git a/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/test_dynamic_column_contract_by_engine.py b/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/test_dynamic_column_contract_by_engine.py index 92ff874493..8addc9e694 100644 --- a/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/test_dynamic_column_contract_by_engine.py +++ b/tests/unit/src/sqlbuild/compiler/compile/_helpers/native_stages/test_dynamic_column_contract_by_engine.py @@ -44,6 +44,7 @@ ( DynamicColumnContractDispatchTestCase( description="native analysis proof replaces the python proof", + native_proof=None, sql_analysis=ModelSqlAnalysis( polyglot_analysis=_ANALYSIS, placeholders=None, @@ -55,6 +56,7 @@ ), DynamicColumnContractDispatchTestCase( description="analysis without a proof falls back to the python proof", + native_proof=None, sql_analysis=ModelSqlAnalysis(polyglot_analysis=_ANALYSIS, placeholders=None), dialect="bigquery", families=(_FAMILY,), @@ -62,13 +64,23 @@ ), DynamicColumnContractDispatchTestCase( description="unanalyzed model falls back to the python proof", + native_proof=None, sql_analysis=None, dialect="bigquery", families=(_FAMILY,), expected_proof=_PYTHON_UNSUPPORTED_PROOF, ), + DynamicColumnContractDispatchTestCase( + description="a batched native proof answers an unanalyzed model", + native_proof=_NATIVE_PROOF, + sql_analysis=None, + dialect="bigquery", + families=(_FAMILY,), + expected_proof=_NATIVE_PROOF, + ), DynamicColumnContractDispatchTestCase( description="model without dynamic families has no proof", + native_proof=None, sql_analysis=ModelSqlAnalysis(polyglot_analysis=_ANALYSIS, placeholders=None), dialect="snowflake", families=(), @@ -82,6 +94,7 @@ def test_given_model_analysis_when_proving_dynamic_contract_then_native_proof_ta ) -> None: proof: DynamicColumnContractProof | None = dynamic_column_contract_by_engine( sql_analysis=test_case.sql_analysis, + native_proof=test_case.native_proof, python_proof=partial( analyze_dynamic_column_contract, query_sql="SELECT * FROM order_amounts", diff --git a/tests/unit/src/sqlbuild/compiler/frontier/_test_types.py b/tests/unit/src/sqlbuild/compiler/frontier/_test_types.py index 232c66c2c5..51aa39f3d7 100644 --- a/tests/unit/src/sqlbuild/compiler/frontier/_test_types.py +++ b/tests/unit/src/sqlbuild/compiler/frontier/_test_types.py @@ -5,7 +5,12 @@ from collections.abc import Callable from dataclasses import dataclass -from sqlbuild.compiler.frontier.types import CompilerEngine, CompilerStage, NativeStage +from sqlbuild.compiler.frontier.types import ( + CompilerEngine, + CompilerStage, + NativeFallbackSite, + NativeStage, +) @dataclass(frozen=True) @@ -143,3 +148,12 @@ class NativeStageCouplingTestCase: dependent: NativeStage dependency: NativeStage expected_engines_without_dependency: frozenset[CompilerEngine] + + +@dataclass(frozen=True) +class NativeFallbackRecorderTestCase: + """Fallbacks one process records and the record file it writes at exit.""" + + description: str + recorded: tuple[tuple[NativeFallbackSite, str], ...] + expected_files: list[list[list[object]]] diff --git a/tests/unit/src/sqlbuild/compiler/frontier/test_native_fallback_recorder.py b/tests/unit/src/sqlbuild/compiler/frontier/test_native_fallback_recorder.py new file mode 100644 index 0000000000..ef6d634e54 --- /dev/null +++ b/tests/unit/src/sqlbuild/compiler/frontier/test_native_fallback_recorder.py @@ -0,0 +1,64 @@ +"""Native-to-Python fallbacks are counted per site and kind and written once per process.""" + +from __future__ import annotations + +import json +import os +from pathlib import Path + +import pytest + +from sqlbuild.compiler.frontier.classes.native_fallback_recorder import NativeFallbackRecorder +from sqlbuild.compiler.frontier.constants import NATIVE_FALLBACK_RECORD_PREFIX +from sqlbuild.compiler.frontier.types import NativeFallbackSite +from tests.unit.src.sqlbuild.compiler.frontier._test_types import NativeFallbackRecorderTestCase + + +@pytest.mark.parametrize( + "test_case", + [ + NativeFallbackRecorderTestCase( + description="counts_per_site_and_kind_sorted", + recorded=( + (NativeFallbackSite.SQL_VARIABLES, "deferred"), + (NativeFallbackSite.REFERENCE_SCAN, "deferred"), + (NativeFallbackSite.SQL_VARIABLES, "deferred"), + (NativeFallbackSite.SQL_VARIABLES, "error"), + ), + expected_files=[ + [ + ["model_loop.sql_variables", "deferred", 2], + ["model_loop.sql_variables", "error", 1], + ["reference_extraction.scan", "deferred", 1], + ] + ], + ), + NativeFallbackRecorderTestCase( + description="no_fallback_writes_no_file", + recorded=(), + expected_files=[], + ), + ], + ids=lambda case: case.description, +) +def test_given_recorded_fallbacks_when_writing_then_one_file_holds_their_counts( + test_case: NativeFallbackRecorderTestCase, tmp_path: Path +) -> None: + recorder: NativeFallbackRecorder = NativeFallbackRecorder(directory=tmp_path / "records") + for site, kind in test_case.recorded: + recorder.record(site=site.value, kind=kind) + + recorder.write() + + written: list[list[list[object]]] = [ + json.loads(path.read_text(encoding="utf-8"))["fallbacks"] + for path in sorted((tmp_path / "records").glob(f"{NATIVE_FALLBACK_RECORD_PREFIX}*")) + ] + assert [path.name for path in (tmp_path / "records").glob("*")] == [ + f"{NATIVE_FALLBACK_RECORD_PREFIX}{os.getpid()}.json" + ] * len(test_case.expected_files) + assert written == test_case.expected_files + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"])