rust-query-macros 0.7.0

Proc-macro crate for rust-query.
Documentation
use std::collections::BTreeMap;

use proc_macro2::{Span, TokenStream};
use quote::format_ident;
use syn::{Attribute, Ident};

#[derive(Clone)]
pub(crate) struct Index {
    pub columns: Vec<Ident>,
    pub kind: IndexKind,
}

#[derive(Clone)]
pub(crate) struct IndexKind {
    pub unique: bool,
    pub span: Span,
}

pub(crate) struct VersionedSchema {
    pub versions: std::ops::Range<u32>,
    pub tables: Vec<VersionedTable>,
    pub use_items: Vec<syn::ItemUse>,
}

// This is a table fully parsed from the schema, it represents multiple versions
pub(crate) struct VersionedTable {
    pub name: Ident,
    pub versions: std::ops::Range<u32>,
    // `prev` always has a distinct span from `name`
    pub prev: Option<Ident>,
    pub indices: Vec<Index>,
    pub doc_comments: Vec<Attribute>,
    pub columns: Vec<VersionedColumn>,
    pub referenceable: bool,
}

pub(crate) struct VersionedColumn {
    pub versions: std::ops::Range<u32>,
    pub name: Ident,
    pub typ: TokenStream,
    pub doc_comments: Vec<Attribute>,
    pub index: Option<IndexKind>,
}

impl VersionedSchema {
    pub fn get(&self, version: u32) -> syn::Result<BTreeMap<usize, SingleVersionTable>> {
        assert!(self.versions.contains(&version));
        let mut tables = BTreeMap::new();
        for (i, t) in self.tables.iter().enumerate() {
            if t.versions.contains(&version) {
                tables.insert(i, self.get_table(t, version)?);
            }
        }
        Ok(tables)
    }

    fn get_table(&self, table: &VersionedTable, version: u32) -> syn::Result<SingleVersionTable> {
        assert!(table.versions.contains(&version));
        let mut columns = BTreeMap::new();
        let mut indices = table.indices.clone();
        for (i, c) in table.columns.iter().enumerate() {
            if c.versions.contains(&version) {
                columns.insert(
                    i,
                    SingleVersionColumn {
                        name: c.name.clone(),
                        typ: c.typ.clone(),
                        is_def: version == c.versions.end - 1,
                        doc_comments: c.doc_comments.clone(),
                    },
                );
                if let Some(kind) = c.index.clone() {
                    indices.push(Index {
                        columns: vec![c.name.clone()],
                        kind,
                    });
                }
            }
        }
        // we don't want to leak the span from table.name into `prev`
        let mut prev = Some(format_ident!("{}", table.name, span = Span::call_site()));
        if version == table.versions.start {
            prev = table.prev.clone();
        }
        if prev.is_some() && version == self.versions.start {
            return Err(syn::Error::new_spanned(
                prev,
                "the previous schema does not exists",
            ));
        }

        Ok(SingleVersionTable {
            prev,
            name: table.name.clone(),
            indices,
            doc_comments: table.doc_comments.clone(),
            columns,
            referenceable: table.referenceable,
        })
    }
}

pub(crate) struct SingleVersionTable {
    pub prev: Option<Ident>,
    pub name: Ident,
    pub indices: Vec<Index>,
    pub doc_comments: Vec<Attribute>,
    pub columns: BTreeMap<usize, SingleVersionColumn>,
    pub referenceable: bool,
}

pub(crate) struct SingleVersionColumn {
    pub name: Ident,
    pub typ: TokenStream,
    // is this the latest version where the column exists?
    pub is_def: bool,
    pub doc_comments: Vec<Attribute>,
}