Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@
## Rust and Native Builds

- Python imports the native extension built from `crates/sqlbuild-python`. After changing any
Rust, rebuild it incrementally with `uv run --no-sync maturin develop --release --skip-install`
Rust, rebuild it incrementally with `make fast-native` (release optimisation, incremental)
before running Python tests. Use one profile consistently within a worktree.
- Always run Python commands with `uv run --no-sync`. A syncing `uv run` or `uv sync` can replace
the locally built extension with a packaged one; if that happens, rebuild with maturin rather
Expand Down
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,11 @@ debug = false

[profile.release]
strip = "symbols"

# Local iteration: release-level optimisation with incremental builds, so rebuilding after a
# focused change does not recompile the whole binding crate. CI and wheels use `release`.
[profile.fast]
inherits = "release"
incremental = true
codegen-units = 256
strip = "none"
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type:
dev-native:
uv run --no-sync maturin develop --profile dev --skip-install

.PHONY: fast-native
fast-native:
uv run --no-sync maturin develop --profile fast --skip-install

rust-check: rust-lint
uv run fensu check
cargo test --workspace --all-features
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ use std::collections::HashSet;
use crate::explicit_references::_helpers::relations::{
ProjectRelation, matched, project_relations,
};
use crate::explicit_references::constants::{
HARD_CODED_RELATION_CODE, HOOK_OWNER, LOADER_OWNER, SOURCE_TYPE,
};
use crate::explicit_references::constants::HARD_CODED_RELATION_CODE;
use crate::explicit_references::errors::ReferenceFailure;
use crate::explicit_references::main::old_name_message::old_name_message;
use crate::explicit_references::main::relation_remedy::relation_remedy;
use crate::explicit_references::models::{
LiteralSql, ReferenceDiagnostic, ReferenceReport, ReferenceRequest, Relation, SqlOwner,
UnmatchedRelation,
Expand Down Expand Up @@ -154,12 +154,7 @@ impl OwnerScan<'_> {

fn message(&self, literal: &LiteralSql, written: &str, found: &ProjectRelation) -> String {
match &found.compatibility_for {
Some(model) => format!(
"{} names '{written}' in SQL passed to ctx.{}(); it is the old name of \
model:{model}, kept only as a compatibility view for consumers outside the \
project",
self.owner.label, literal.method
),
Some(model) => old_name_message(&self.owner.label, written, &literal.method, model),
None => format!(
"{} names {}:{} as '{written}' in SQL passed to ctx.{}()",
self.owner.label, found.target.0, found.target.1, literal.method
Expand All @@ -178,43 +173,14 @@ impl OwnerScan<'_> {
};
format!(
"{}{qualify}\n = help: {}",
self.remedy(&found.target),
relation_remedy(
&self.owner.kind,
&found.target,
&self.owner.upstream_loaders
),
self.request.explicit_help
)
}

/// `hard_coded_relation_remedy_impl`.
fn remedy(&self, (kind, name): &ResourceKey) -> String {
let typed: String = format!("{kind}(\"{name}\")");
if self.owner.kind == LOADER_OWNER {
if kind != SOURCE_TYPE {
return format!(
"loaders run before models and seeds and cannot read them; read \
{kind}:{name} from a task or asset instead"
);
}
return match self
.owner
.upstream_loaders
.iter()
.find(|(source, _)| source == name)
{
Some((_, loader)) => {
format!("use ctx.loader({loader}) instead of the relation name")
}
None => format!("use ctx.source(\"{name}\") instead of the relation name"),
};
}
let declaration: String = if self.owner.kind == HOOK_OWNER {
format!("@hook(reads={typed})")
} else {
format!("depends_on={typed}")
};
format!(
"declare it with {declaration} and use ctx.relation({typed}) instead of the relation \
name"
)
}
}

fn extracted(
Expand Down
2 changes: 2 additions & 0 deletions crates/sqlbuild-analysis/src/explicit_references/main/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
pub mod check_explicit_references;
pub mod execution_gate_edges;
pub mod old_name_message;
pub mod relation_remedy;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! The P008 message for SQL naming a relation kept only as a compatibility view.

/// `old_name_reference_message`: `owner_label` wrote `written` in SQL passed to `ctx.<method>()`.
#[must_use]
pub fn old_name_message(
owner_label: &str,
written: &str,
method: &str,
model_name: &str,
) -> String {
format!(
"{owner_label} names '{written}' in SQL passed to ctx.{method}(); it is the old name of \
model:{model_name}, kept only as a compatibility view for consumers outside the project"
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//! How Python code should read a project resource instead of naming its relation in SQL.

use crate::explicit_references::constants::{HOOK_OWNER, LOADER_OWNER, SOURCE_TYPE};
use crate::explicit_references::types::ResourceKey;

/// `hard_coded_relation_remedy`; `upstream_loaders` maps sources to the loaders writing them.
#[must_use]
pub fn relation_remedy(
owner_kind: &str,
(kind, name): &ResourceKey,
upstream_loaders: &[(String, String)],
) -> String {
let typed: String = format!("{kind}(\"{name}\")");
if owner_kind == LOADER_OWNER {
if kind != SOURCE_TYPE {
return format!(
"loaders run before models and seeds and cannot read them; read \
{kind}:{name} from a task or asset instead"
);
}
return match upstream_loaders.iter().find(|(source, _)| source == name) {
Some((_, loader)) => format!("use ctx.loader({loader}) instead of the relation name"),
None => format!("use ctx.source(\"{name}\") instead of the relation name"),
};
}
let declaration: String = if owner_kind == HOOK_OWNER {
format!("@hook(reads={typed})")
} else {
format!("depends_on={typed}")
};
format!(
"declare it with {declaration} and use ctx.relation({typed}) instead of the relation name"
)
}
1 change: 1 addition & 0 deletions crates/sqlbuild-analysis/src/semantic_checks/main/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod complete_semantic_diagnostics;
pub mod finish_type_recovery;
pub mod plan_type_recovery;
pub mod resource_sql_diagnostics;
pub mod semantic_help_catalogue;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! The code-owned remediation of each semantic diagnostic code.

use crate::semantic_checks::constants::SEMANTIC_HELP;

/// Each semantic diagnostic code and its help, in catalogue order.
#[must_use]
pub fn semantic_help_catalogue() -> &'static [(&'static str, &'static str)] {
SEMANTIC_HELP
}
Loading
Loading