use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, LitStr, parse_macro_input};
mod generators;
mod macros;
mod plugins;
mod schema_reader;
mod types;
use generators::{
generate_enum_module, generate_model_module_with_style, generate_type_module,
generate_view_module,
};
#[proc_macro]
pub fn prax_schema(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let schema_path = input.value();
match generate_from_schema(&schema_path) {
Ok(tokens) => tokens.into(),
Err(err) => {
let err_msg = err.to_string();
quote! {
compile_error!(#err_msg);
}
.into()
}
}
}
#[proc_macro_derive(Model, attributes(prax))]
pub fn derive_model(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
match generators::derive_model_impl(&input) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
}
#[proc_macro]
pub fn find_many(input: TokenStream) -> TokenStream {
match macros::ops::find_many::expand_find_many(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn find_unique(input: TokenStream) -> TokenStream {
match macros::ops::find_unique::expand_find_unique(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn find_first(input: TokenStream) -> TokenStream {
match macros::ops::find_first::expand_find_first(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn count(input: TokenStream) -> TokenStream {
match macros::ops::count::expand_count(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn aggregate(input: TokenStream) -> TokenStream {
match macros::ops::aggregate::expand_aggregate(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn group_by(input: TokenStream) -> TokenStream {
match macros::ops::group_by::expand_group_by(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn delete(input: TokenStream) -> TokenStream {
match macros::ops::delete::expand_delete(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn delete_many(input: TokenStream) -> TokenStream {
match macros::ops::delete_many::expand_delete_many(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn r#where(input: TokenStream) -> TokenStream {
match macros::ops::shape::expand_where_shape(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn include(input: TokenStream) -> TokenStream {
match macros::ops::shape::expand_include_shape(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn select(input: TokenStream) -> TokenStream {
match macros::ops::shape::expand_select_shape(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn order_by(input: TokenStream) -> TokenStream {
match macros::ops::shape::expand_order_by_shape(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn create(input: TokenStream) -> TokenStream {
match macros::ops::create::expand_create(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn update(input: TokenStream) -> TokenStream {
match macros::ops::update::expand_update(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn upsert(input: TokenStream) -> TokenStream {
match macros::ops::upsert::expand_upsert(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn create_many(input: TokenStream) -> TokenStream {
match macros::ops::create_many::expand_create_many(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn update_many(input: TokenStream) -> TokenStream {
match macros::ops::update_many::expand_update_many(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
#[proc_macro]
pub fn cursor(input: TokenStream) -> TokenStream {
match macros::ops::shape::expand_cursor_shape(input.into()) {
Ok(t) => t.into(),
Err(e) => e.to_compile_error().into(),
}
}
fn generate_from_schema(schema_path: &str) -> Result<proc_macro2::TokenStream, syn::Error> {
use plugins::{PluginConfig, PluginContext, PluginRegistry};
use schema_reader::read_schema_with_config;
let schema_with_config = read_schema_with_config(schema_path).map_err(|e| {
syn::Error::new(
proc_macro2::Span::call_site(),
format!("Failed to parse schema: {}", e),
)
})?;
let schema = schema_with_config.schema;
let model_style = schema_with_config.model_style;
let plugin_config = PluginConfig::with_model_style(model_style);
let plugin_registry = PluginRegistry::with_builtins();
let plugin_ctx = PluginContext::new(&schema, &plugin_config);
let mut output = proc_macro2::TokenStream::new();
let start_output = plugin_registry.run_start(&plugin_ctx);
output.extend(start_output.tokens);
output.extend(start_output.root_items);
for (_, enum_def) in &schema.enums {
output.extend(generate_enum_module(enum_def)?);
let plugin_output = plugin_registry.run_enum(&plugin_ctx, enum_def);
if !plugin_output.is_empty() {
output.extend(plugin_output.tokens);
}
}
for (_, type_def) in &schema.types {
output.extend(generate_type_module(type_def)?);
let plugin_output = plugin_registry.run_type(&plugin_ctx, type_def);
if !plugin_output.is_empty() {
output.extend(plugin_output.tokens);
}
}
for (_, view_def) in &schema.views {
output.extend(generate_view_module(view_def)?);
let plugin_output = plugin_registry.run_view(&plugin_ctx, view_def);
if !plugin_output.is_empty() {
output.extend(plugin_output.tokens);
}
}
for (_, model_def) in &schema.models {
output.extend(generate_model_module_with_style(
model_def,
&schema,
model_style,
)?);
let plugin_output = plugin_registry.run_model(&plugin_ctx, model_def);
if !plugin_output.is_empty() {
output.extend(plugin_output.tokens);
}
}
let finish_output = plugin_registry.run_finish(&plugin_ctx);
output.extend(finish_output.tokens);
output.extend(finish_output.root_items);
output.extend(plugins::generate_plugin_docs(&plugin_registry));
Ok(output)
}