Skip to main content

razeri_plugin_contract/
lib.rs

1// Copyright (C) 2026 Gabriel Shea
2// Licensed under either of the Apache License, Version 2.0 or the MIT
3// license, at your option.
4
5#![warn(missing_docs)]
6
7//! # razeri-plugin-contract
8//!
9//! **The contract a Razeri dialect plugin is written against.**
10//!
11//! This crate and `razeri-plugin-api` are the two open crates in Razeri's
12//! workspace. Everything a plugin author needs in order to *describe* and
13//! *render* a database platform lives here; nothing else does. It depends on
14//! `serde` and on nothing else at all, which is what lets a plugin be built,
15//! published and consumed outside this repository.
16//!
17//! ## What is in here
18//!
19//! **The rendering hierarchy** — ten traits, layered so that a new dialect
20//! implements four required methods and inherits ANSI-standard behaviour for
21//! the rest:
22//!
23//! 1. [`SqlRenderer`] — core SQL rendering (the four required methods)
24//! 2. [`ExpressionRenderer`] — expressions, with ANSI defaults
25//! 3. [`DdlRenderer`] — DDL, with ANSI defaults
26//! 4. [`DmlRenderer`] — DML, with ANSI defaults
27//! 5. [`ProcedureRenderer`] — stored procedures and functions
28//! 6. [`FormulaRenderer`] — formulas, with ANSI defaults
29//! 7. [`TaskRenderer`] — scheduled tasks
30//! 8. [`ReplicationRenderer`] — data extraction, loading and key-function deployment
31//! 9. [`StorageRenderer`] — partitioning, compression and index strategy
32//! 10. [`DialectCapabilities`] — what the platform's SQL can and cannot do
33//!
34//! **The vocabulary those traits speak**: [`DataType`] and [`DataTypeRef`], the
35//! [`storage_strategy::StoragePlan`] a [`StorageRenderer`] translates, the
36//! [`StoragePlatform`] a storage plugin names, and [`DialectFamily`], the
37//! platform's own identity.
38//!
39//! **The spelling a source gives a day** — [`date_format`]. One import
40//! arrives with `1/1/2015` in one column and `2015-01-01T00:00:00Z` in the
41//! next; the design states the spelling, this crate reads it once into a list
42//! of directives, and each engine translates that list into its own pattern
43//! language through [`ExpressionRenderer::render_parse_datetime`]. A directive
44//! an engine cannot spell is refused by name.
45//!
46//! **The fan-out an engine states** — [`flatten`]. One row holding an array
47//! becomes one row per element, and every engine spells that differently, so
48//! the dialect answers with the whole shape rather than filling in a template.
49//!
50//! **The decisions a dialect states rather than a core crate deciding for it**,
51//! starting with [`SidSpelling`] — how this engine spells a surrogate key —
52//! and continuing with [`ProcedureForm`] and [`ScalarFunctionForm`], the
53//! routine grammars it speaks, [`MergeShape`], how it upserts, and
54//! [`EvolutionAnswers`], what it keeps when a table that already holds rows
55//! changes shape.
56//!
57//! **The surrogate key's composition** — [`sid`] turns a [`SidSpelling`] into
58//! the key expression an engine runs. It is here rather than in the product
59//! because a dialect author who cannot render their own key expression cannot
60//! run it either, and *"the same key on every engine"* is then a claim nobody
61//! outside this repository can check.
62//!
63//! **The named routine grammars, spelled** — [`routine_render`]. A dialect
64//! whose engine has stored procedures in a grammar of its own renders the whole
65//! `CREATE` itself, and *"PL/pgSQL with one tweak"* used to mean writing the
66//! whole thing from nothing. These three functions write out the grammar a
67//! dialect is nearly the same as, so it can start there and say what differs.
68//!
69//! ## What is deliberately not in here
70//!
71//! Razeri's design model, and the renderers that turn it into Razeri's own
72//! output. A plugin says what its engine spells; Razeri composes. That division
73//! is why one contract crate can be open while the product is not.
74//!
75//! The routine grammars are the one thing on both sides of that line, and they
76//! are here because they belong to the engines rather than to Razeri's design: a
77//! plugin author who cannot read the grammar next to theirs has to guess at it.
78//!
79//! ## How this crate is versioned
80//!
81//! While the major version is zero:
82//!
83//! - **a change to a trait's method set bumps the minor version** — a method
84//!   added, removed or renamed, whether or not it carries a default body;
85//! - **documentation and fixes bump the patch version.**
86//!
87//! The rule is about who decides when a plugin's behaviour changes. Cargo
88//! flows a patch release to every plugin pinned at the minor the next time it
89//! builds, and flows a minor release to nobody. A defaulted method costs an
90//! existing plugin no line of code, and it still changes what that plugin
91//! *says*: an engine that has not implemented the new method now answers the
92//! default, and its users meet whatever Razeri does with that answer — a
93//! refusal they had never seen, arriving because somebody else released. So a
94//! new method is opted into, and the plugin author chooses the day.
95//!
96//! This is stricter than semantic versioning requires of a zero-major crate,
97//! deliberately: the looser reading saves a version number and spends a
98//! plugin author's afternoon.
99//!
100//! ### What 0.5.0 adds to the method set
101//!
102//! - [`StorageRenderer::render_partition_retain_procedure`] takes the
103//!   companion table a load sets rows aside in, so one call to a retention
104//!   procedure reaches both tables.
105//! - [`ExpressionRenderer::render_parse_datetime`] renders the parse of a
106//!   value the source spells its own way into a date or a timestamp.
107
108pub mod agnostic;
109pub mod capabilities;
110pub mod constraint_enforcement;
111pub mod data_type;
112pub mod date_format;
113pub mod dialect_family;
114pub mod evolution;
115pub mod flatten;
116pub mod formula_renderer;
117pub mod merge_shape;
118pub mod procedure_log_level;
119pub mod renderer;
120pub mod replication;
121pub mod routine_form;
122pub mod routine_render;
123pub mod routine_spec;
124pub mod sid;
125pub mod sid_spelling;
126pub mod storage_platform;
127pub mod storage_renderer;
128pub mod storage_strategy;
129pub mod task_renderer;
130
131pub use agnostic::*;
132pub use capabilities::*;
133pub use constraint_enforcement::*;
134pub use data_type::{DataType, DataTypeRef};
135pub use date_format::{DateFormat, DateFormatError, FormatDirective, FormatPart};
136pub use dialect_family::DialectFamily;
137pub use evolution::*;
138pub use flatten::{Flatten, FlattenField, FlattenRequest};
139pub use formula_renderer::*;
140pub use merge_shape::*;
141pub use procedure_log_level::ProcedureLogLevel;
142pub use renderer::*;
143pub use replication::*;
144pub use routine_form::*;
145pub use routine_render::{
146    render_procedure_as, render_scalar_function_as, render_table_function_as,
147};
148pub use routine_spec::*;
149pub use sid::sid_expression;
150pub use sid_spelling::*;
151pub use storage_platform::StoragePlatform;
152pub use storage_renderer::*;
153pub use task_renderer::*;