Expand description
§razeri-plugin-contract
The contract a Razeri dialect plugin is written against.
This crate and razeri-plugin-api are the two open crates in Razeri’s
workspace. Everything a plugin author needs in order to describe and
render a database platform lives here; nothing else does. It depends on
serde and on nothing else at all, which is what lets a plugin be built,
published and consumed outside this repository.
§What is in here
The rendering hierarchy — ten traits, layered so that a new dialect implements four required methods and inherits ANSI-standard behaviour for the rest:
SqlRenderer— core SQL rendering (the four required methods)ExpressionRenderer— expressions, with ANSI defaultsDdlRenderer— DDL, with ANSI defaultsDmlRenderer— DML, with ANSI defaultsProcedureRenderer— stored procedures and functionsFormulaRenderer— formulas, with ANSI defaultsTaskRenderer— scheduled tasksReplicationRenderer— data extraction, loading and key-function deploymentStorageRenderer— partitioning, compression and index strategyDialectCapabilities— what the platform’s SQL can and cannot do
The vocabulary those traits speak: DataType and DataTypeRef, the
storage_strategy::StoragePlan a StorageRenderer translates, the
StoragePlatform a storage plugin names, and DialectFamily, the
platform’s own identity.
The spelling a source gives a day — date_format. One import
arrives with 1/1/2015 in one column and 2015-01-01T00:00:00Z in the
next; the design states the spelling, this crate reads it once into a list
of directives, and each engine translates that list into its own pattern
language through ExpressionRenderer::render_parse_datetime. A directive
an engine cannot spell is refused by name.
The way a source writes an amount — number_format. A file writes a
price $2,899.99 , where the symbol, the thousands mark and the space
around it are not part of the number. The design states the picture, this
crate reads it once into the marks that are not part of the value, and each
engine takes those marks out and converts what is left through
ExpressionRenderer::render_parse_number. An engine that states nothing
is refused by name rather than guessed for.
The questions asked of a warehouse that is already there —
SqlRenderer::render_catalog_columns_query and
SqlRenderer::render_catalog_object_times_query. A design says what
would be built; how much of a running warehouse was built is a question
only that warehouse answers, so each engine spells the two queries that
ask it and names the schemas a whole-warehouse scan passes over through
SqlRenderer::catalog_system_schemas. None is a complete answer to
either query: an engine with no catalog to read is named rather than
reported as an empty warehouse.
The fan-out an engine states — flatten. One row holding an array
becomes one row per element, and every engine spells that differently, so
the dialect answers with the whole shape rather than filling in a template.
The decisions a dialect states rather than a core crate deciding for it,
starting with SidSpelling — how this engine spells a surrogate key —
and continuing with ProcedureForm and ScalarFunctionForm, the
routine grammars it speaks, MergeShape, how it upserts, and
EvolutionAnswers, what it keeps when a table that already holds rows
changes shape.
The surrogate key’s composition — sid turns a SidSpelling into
the key expression an engine runs. It is here rather than in the product
because a dialect author who cannot render their own key expression cannot
run it either, and “the same key on every engine” is then a claim nobody
outside this repository can check.
The named routine grammars, spelled — routine_render. A dialect
whose engine has stored procedures in a grammar of its own renders the whole
CREATE itself, and “PL/pgSQL with one tweak” used to mean writing the
whole thing from nothing. These three functions write out the grammar a
dialect is nearly the same as, so it can start there and say what differs.
§What is deliberately not in here
Razeri’s design model, and the renderers that turn it into Razeri’s own output. A plugin says what its engine spells; Razeri composes. That division is why one contract crate can be open while the product is not.
The routine grammars are the one thing on both sides of that line, and they are here because they belong to the engines rather than to Razeri’s design: a plugin author who cannot read the grammar next to theirs has to guess at it.
§How this crate is versioned
While the major version is zero:
- a change to a trait’s method set bumps the minor version — a method added, removed or renamed, whether or not it carries a default body;
- documentation and fixes bump the patch version.
The rule is about who decides when a plugin’s behaviour changes. Cargo flows a patch release to every plugin pinned at the minor the next time it builds, and flows a minor release to nobody. A defaulted method costs an existing plugin no line of code, and it still changes what that plugin says: an engine that has not implemented the new method now answers the default, and its users meet whatever Razeri does with that answer — a refusal they had never seen, arriving because somebody else released. So a new method is opted into, and the plugin author chooses the day.
This is stricter than semantic versioning requires of a zero-major crate, deliberately: the looser reading saves a version number and spends a plugin author’s afternoon.
§What 0.5.0 adds to the method set
StorageRenderer::render_partition_retain_proceduretakes the companion table a load sets rows aside in, so one call to a retention procedure reaches both tables.ExpressionRenderer::render_parse_datetimerenders the parse of a value the source spells its own way into a date or a timestamp.SqlRenderer::delimited_file_relation_in_encodingreads a delimited file whose bytes are not UTF-8, where the engine states a way to.
§What 0.6.0 adds to the method set
SqlRenderer::render_catalog_columns_queryasks a running warehouse what it holds, one row per column.SqlRenderer::render_catalog_object_times_queryasks when each object was created, where the engine records it at all.SqlRenderer::catalog_system_schemasnames the schemas a whole-warehouse scan passes over, andSqlRenderer::catalog_scope_predicateis theWHEREclause both catalog queries share.ExpressionRenderer::render_parse_numberrenders the reading of a value the source writes its own way into a number.StorageRenderer::slice_replacement_is_procedure_bodysays whether the slice replacement this engine rendered runs on its own or only inside a procedure. Left alone, the shape of the answer is read instead.
Beside the method set, sid::normalize_trim is now public: the TRIM in
an engine’s own spelling, which both the canonical normalization and the
reading of a written amount start from.
Re-exports§
pub use data_type::DataType;pub use data_type::DataTypeRef;pub use date_format::DateFormat;pub use date_format::DateFormatError;pub use date_format::FormatDirective;pub use date_format::FormatPart;pub use dialect_family::DialectFamily;pub use flatten::Flatten;pub use flatten::FlattenField;pub use flatten::FlattenRequest;pub use number_format::Negatives;pub use number_format::NumberFormat;pub use number_format::NumberFormatError;pub use procedure_log_level::ProcedureLogLevel;pub use routine_render::render_procedure_as;pub use routine_render::render_scalar_function_as;pub use routine_render::render_table_function_as;pub use sid::sid_expression;pub use storage_platform::StoragePlatform;pub use agnostic::*;pub use capabilities::*;pub use constraint_enforcement::*;pub use evolution::*;pub use formula_renderer::*;pub use merge_shape::*;pub use renderer::*;pub use replication::*;pub use routine_form::*;pub use routine_spec::*;pub use sid_spelling::*;pub use storage_renderer::*;pub use task_renderer::*;
Modules§
- agnostic
- Agnostic dialect and ANSI data-type rendering.
- capabilities
- Boolean capability flags with conservative defaults.
- constraint_
enforcement - Whether this engine actually checks the constraints it accepts — the dialect’s answer, and the one place the rendered DDL and the docs read it from.
- data_
type - Generic data types for cross-database compatibility.
- date_
format - How a source spells a day — the format a design states, read once and handed to every engine as a list rather than as text.
- dialect_
family - Dialect Family Definitions
- evolution
- Changing a table that already holds rows — what this engine keeps through such a change, and the statement it takes to make one.
- flatten
- One row holding an array becomes one row per element — the vocabulary an engine answers a fan-out in.
- formula_
renderer - Formula-level rendering extensions with ANSI defaults.
- merge_
shape - How this engine performs an upsert — a shape the dialect describes, not a switch it flips.
- number_
format - How a source writes an amount — the picture a design states, read once and handed to every engine as a small set of facts rather than as text.
- procedure_
log_ level - How loud a message a procedure body writes is.
- renderer
- Layered rendering traits for SQL generation.
- replication
- Replication rendering traits with ANSI defaults.
- routine_
form - Which routine grammar this engine speaks — the dialect’s answer, not a core crate’s guess about its name.
- routine_
render - The named routine grammars, rendered where a plugin can reach them.
- routine_
spec - The routine Razeri composed, handed to a dialect that spells its own grammar.
- sid
- The one derivation of a surrogate key, composed from the vocabulary a dialect states.
- sid_
spelling - How this engine spells a surrogate key — the one thing about the key a dialect decides.
- storage_
platform - Storage platform enumeration for raw file management.
- storage_
renderer - Storage rendering trait for partition, compression, and index strategies.
- storage_
strategy - Agnostic storage strategy types: partition, compression, index.
- task_
renderer - Task and schedule rendering extensions.