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 crates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ that can be tested and benchmarked with `cargo test` alone.
| Crate | Responsibility |
|---|---|
| `sqlbuild-core` | Constants shared by several crates, the panic boundary that turns an unwinding native failure into a named compiler error, passive identity, diagnostic and SQL value types, text positions, and a JSON emitter whose output matches Python's `json.dumps` and `orjson` byte for byte. |
| `sqlbuild-sqltext` | Lexical SQL text without polyglot: comment, quote and parenthesis scanning, the rules quote policy, model header tokenization and matching, static variable substitution and static reference extraction. |
| `sqlbuild-sqltext` | Lexical SQL text without polyglot: comment, quote and parenthesis scanning, the rules quote policy, model header tokenization and matching, static variable substitution, static reference extraction, and the general reference scan with table-function call arguments under each adapter's lexical rules. |
| `sqlbuild-config` | Configuration file reading without Python: `tomllib`-compatible TOML, PyYAML `safe_load`-compatible YAML 1.1, and typed project and local config readers for the fields discovery needs. Errors carry their kind and position; YAML outside the supported subset is an `Unsupported` error. |
| `sqlbuild-discovery` | Native project discovery and the only implementation of the model, SQL test, scenario, source and schema file collections and the declaration layout: the shared directory walk with Python's glob and sort semantics, file reading with Python's newline handling and read errors, and parsing of authored files with Python's exact discovery messages. Results are plain data the Python discovery facade materialises. |
| `sqlbuild-scopes` | Declaration scopes: the scope index with Python's record orders and diagnostics, declaration visibility, relationship grants, the scope lookup groups, and the dialect-aware scan of SQL tests and scenarios for their expected models. Anything it cannot reproduce exactly defers to Python. |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,15 @@
//! Expected-model relationship names of SQL tests and scenarios, scanned natively.

use pyo3::prelude::{Bound, PyModule, PyModuleMethods, PyResult, Python};
use pyo3::{FromPyObject, pyfunction, wrap_pyfunction};
use pyo3::{pyfunction, wrap_pyfunction};
use sqlbuild_scopes::relationship_names::main::expected_model_names::expected_model_names;
use sqlbuild_scopes::relationship_names::models::ExpectedNames;
use sqlbuild_sqltext::sql_scan::models::LexicalSyntax;

use crate::bindings::_helpers::boundary::panics::compiler_error;
use crate::bindings::_helpers::sqltext::lexical_syntax::LexicalSyntaxInput;
use crate::bindings::types::CompilerDetach;

/// One adapter's `SqlLexicalSyntax`, read from a Python mapping.
#[derive(FromPyObject)]
#[pyo3(from_item_all)]
struct LexicalSyntaxInput {
backslash_escape_quotes: Vec<String>,
escape_string_prefix: bool,
raw_string_prefix: bool,
triple_quoted_strings: bool,
nested_block_comments: bool,
line_comment_prefixes: Vec<String>,
}

impl From<LexicalSyntaxInput> for LexicalSyntax {
fn from(input: LexicalSyntaxInput) -> Self {
Self {
backslash_escape_quotes: input.backslash_escape_quotes,
escape_string_prefix: input.escape_string_prefix,
raw_string_prefix: input.raw_string_prefix,
triple_quoted_strings: input.triple_quoted_strings,
nested_block_comments: input.nested_block_comments,
line_comment_prefixes: input.line_comment_prefixes,
}
}
}

/// Return each body's expected-model names, or `None` where Python must extract them.
#[pyfunction]
fn scope_expected_model_names(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//! One adapter's `SqlLexicalSyntax`, read from a Python mapping.

use pyo3::FromPyObject;
use sqlbuild_sqltext::sql_scan::models::LexicalSyntax;

/// One adapter's `SqlLexicalSyntax`, read from a Python mapping.
#[derive(FromPyObject)]
#[pyo3(from_item_all)]
pub(crate) struct LexicalSyntaxInput {
backslash_escape_quotes: Vec<String>,
escape_string_prefix: bool,
raw_string_prefix: bool,
triple_quoted_strings: bool,
nested_block_comments: bool,
line_comment_prefixes: Vec<String>,
}

impl From<LexicalSyntaxInput> for LexicalSyntax {
fn from(input: LexicalSyntaxInput) -> Self {
Self {
backslash_escape_quotes: input.backslash_escape_quotes,
escape_string_prefix: input.escape_string_prefix,
raw_string_prefix: input.raw_string_prefix,
triple_quoted_strings: input.triple_quoted_strings,
nested_block_comments: input.nested_block_comments,
line_comment_prefixes: input.line_comment_prefixes,
}
}
}
3 changes: 3 additions & 0 deletions crates/sqlbuild-python/src/bindings/_helpers/sqltext/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub(crate) mod authored_values;
pub(crate) mod lexical_syntax;
pub(crate) mod model_headers;
pub(crate) mod registration;
pub(crate) mod sql_references;
pub(crate) mod static_sql;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Register the lexical SQL text functions and classes.

use pyo3::prelude::{Bound, PyModule, PyResult};

use crate::bindings::_helpers::sqltext::{model_headers, sql_references, static_sql};

pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
model_headers::register(module)?;
static_sql::register(module)?;
sql_references::register(module)?;
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//! Logical SQL references extracted natively under one adapter's lexical rules.

use pyo3::prelude::{Bound, PyModule, PyModuleMethods, PyResult};
use pyo3::{pyclass, pymethods};
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::bindings::_helpers::boundary::panics::compiler_guard;
use crate::bindings::_helpers::sqltext::lexical_syntax::LexicalSyntaxInput;

/// `(kind, name, package, call_argument_count)` for one reference.
type ReferenceRow = (&'static str, String, Option<String>, Option<usize>);
/// The references, or Python's error message; `None` defers the text to Python.
type ExtractionRow = Option<(Option<Vec<ReferenceRow>>, Option<String>)>;

/// Extracts references under one adapter's lexical rules, read once per syntax.
#[pyclass(module = "sqlbuild._native", frozen)]
pub(crate) struct SqlReferenceScanner {
syntax: LexicalSyntax,
}

#[pymethods]
impl SqlReferenceScanner {
#[new]
fn new(syntax: LexicalSyntaxInput) -> Self {
Self {
syntax: syntax.into(),
}
}

/// Return `(references, None)`, `(None, message)` when Python raises, or `None` to defer.
fn extract(&self, sql: &str) -> PyResult<ExtractionRow> {
compiler_guard(|| {
Ok(match extract_sql_references(sql, &self.syntax) {
ReferenceExtraction::Extracted(references) => Some((
Some(references.into_iter().map(reference_row).collect()),
None,
)),
ReferenceExtraction::Failed(message) => Some((None, Some(message))),
ReferenceExtraction::Deferred => None,
})
})
}
}

fn reference_row(reference: SqlReference) -> ReferenceRow {
(
reference.kind,
reference.name,
reference.package,
reference.call_argument_count,
)
}

pub(crate) fn register(module: &Bound<'_, PyModule>) -> PyResult<()> {
module.add_class::<SqlReferenceScanner>()?;
Ok(())
}
3 changes: 1 addition & 2 deletions crates/sqlbuild-python/src/bindings/main/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ pub fn _native(module: &Bound<'_, PyModule>) -> PyResult<()> {
analysis::normalization::register(module)?;
analysis::queries::register(module)?;
analysis::sql_tests::register(module)?;
sqltext::model_headers::register(module)?;
sqltext::static_sql::register(module)?;
sqltext::registration::register(module)?;
boundary::oracles::register(module)?;
discovery::project_files::register(module)?;
scopes::scope_index::register(module)?;
Expand Down
1 change: 1 addition & 0 deletions crates/sqlbuild-sqltext/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@

pub mod compiler;
mod constants;
pub mod sql_references;
pub mod sql_scan;
1 change: 1 addition & 0 deletions crates/sqlbuild-sqltext/src/sql_references/_helpers/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub(crate) mod scan;
Loading
Loading