Skip to content

Commit

Permalink
Implement embed_migration! using macros 1.1
Browse files Browse the repository at this point in the history
* port embed_migration to macros 1.1
* remove codegen_old
* some minor fixes
  • Loading branch information
weiznich committed Oct 10, 2016
1 parent ce31e82 commit 88c5f7a
Show file tree
Hide file tree
Showing 29 changed files with 259 additions and 356 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ script:
fi &&
(cd diesel_cli && travis-cargo test -- --no-default-features --features "$BACKEND") &&
if [[ "$TRAVIS_RUST_VERSION" == nightly* ]]; then
(cd diesel_codegen_syntex && travis-cargo test -- --no-default-features --features "$BACKEND")
(cd diesel_codegen && travis-cargo test -- --no-default-features --features "$BACKEND")
else
(cd diesel_codegen_syntex && travis-cargo test -- --no-default-features --features "with-syntex $BACKEND")
fi &&
Expand Down
29 changes: 29 additions & 0 deletions diesel/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,35 @@ macro_rules! infer_table_from_schema {
}
}

#[macro_export]
/// This macro will read your migrations at compile time, and embed a module you can
/// use to execute them at runtime without the migration files being present on the
/// file system. This is useful if you would like to use Diesel's migration
/// infrastructure, but want to ship a single executable file (such as for embedded
/// applications). It can also be used to apply migrations to an in memory database
/// (Diesel does this for its own test suite).
///
/// You can optionally pass the path to the migrations directory to this macro. When
/// left unspecified, Diesel Codegen will search for the migrations directory in the
/// same way that Diesel CLI does. If specified, the path should be relative to the
/// directory containing your Cargo.toml (CARGO_MANIFEST_HOME)
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
///
/// FIXME: Oh look we have a place to actually document this now.
macro_rules! embed_migrations {
() => {
#[derive(Embed_Migrations)]
struct Migrations;
};
($migration_path: expr) => {
#[derive(EmbeddedMigrations)]
#[options(migration_path=$migration_path)]
struct Migrations;
}
}

// The order of these modules is important (at least for those which have tests).
// Utililty macros which don't call any others need to come first.
#[macro_use] mod parse;
Expand Down
23 changes: 23 additions & 0 deletions diesel/src/migrations/embedded_migration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use super::{Migration, RunMigrationsError};
use ::connection::SimpleConnection;

#[derive(Debug)]
#[allow(missing_copy_implementations)]
pub struct EmbeddedMigration {
pub version: &'static str,
pub up_sql: &'static str,
}

impl Migration for EmbeddedMigration {
fn version(&self) -> &str {
self.version
}

fn run(&self, conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
conn.batch_execute(self.up_sql).map_err(Into::into)
}

fn revert(&self, _conn: &SimpleConnection) -> Result<(), RunMigrationsError> {
unreachable!()
}
}
2 changes: 2 additions & 0 deletions diesel/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub mod connection;
mod migration_error;
#[doc(hidden)]
pub mod schema;
mod embedded_migration;
pub use self::embedded_migration::EmbeddedMigration;

#[doc(inline)]
pub use self::connection::MigrationConnection;
Expand Down
2 changes: 2 additions & 0 deletions diesel_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ authors = ["Sean Griffin <sean@seantheprogrammer.com>"]
syn = "0.8.5"
quote = "0.2.1"
diesel_codegen_shared = { path = "../diesel_codegen_shared", default-features = false }
diesel = {version = "0.7", default-features = false }


[lib]
rustc-macro = true
Expand Down
4 changes: 2 additions & 2 deletions diesel_codegen/src/associations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ fn to_foreign_key(model_name: &str) -> syn::Ident {

#[test]
fn to_foreign_key_properly_handles_underscores() {
assert_eq!(str_to_ident("foo_bar_id"), to_foreign_key("FooBar"));
assert_eq!(str_to_ident("foo_bar_baz_id"), to_foreign_key("FooBarBaz"));
assert_eq!(syn::Ident::new("foo_bar_id"), to_foreign_key("FooBar"));
assert_eq!(syn::Ident::new("foo_bar_baz_id"), to_foreign_key("FooBarBaz"));
}
24 changes: 16 additions & 8 deletions diesel_codegen/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(rustc_macro, rustc_macro_lib)]
#![deny(warnings)]
#![recursion_limit = "512"]

macro_rules! t {
($expr:expr) => {
Expand All @@ -10,7 +11,6 @@ macro_rules! t {
};
}

#[cfg(any(feature = "postgres", feature = "sqlite"))]
extern crate diesel_codegen_shared;
#[macro_use]
extern crate quote;
Expand All @@ -28,6 +28,7 @@ mod queryable;
#[cfg(any(feature = "postgres", feature = "sqlite"))]
mod schema_inference;
mod util;
mod migrations;

use rustc_macro::TokenStream;
use syn::parse_macro_input;
Expand All @@ -53,47 +54,54 @@ const KNOWN_FIELD_ATTRIBUTES: &'static [&'static str] = &[
"column_name",
];

#[rustc_macro_derive(Queryable)]
#[cfg_attr(not(test), rustc_macro_derive(Queryable))]
pub fn derive_queryable(input: TokenStream) -> TokenStream {
expand_derive(input, queryable::derive_queryable)
}

#[rustc_macro_derive(Identifiable)]
#[cfg_attr(not(test), rustc_macro_derive(Identifiable))]
pub fn derive_identifiable(input: TokenStream) -> TokenStream {
expand_derive(input, identifiable::derive_identifiable)
}

#[rustc_macro_derive(Insertable)]
#[cfg_attr(not(test), rustc_macro_derive(Insertable))]
pub fn derive_insertable(input: TokenStream) -> TokenStream {
expand_derive(input, insertable::derive_insertable)
}

#[rustc_macro_derive(AsChangeset)]
#[cfg_attr(not(test), rustc_macro_derive(AsChangeset))]
pub fn derive_as_changeset(input: TokenStream) -> TokenStream {
expand_derive(input, as_changeset::derive_as_changeset)
}

#[rustc_macro_derive(Associations)]
#[cfg_attr(not(test), rustc_macro_derive(Associations))]
pub fn derive_associations(input: TokenStream) -> TokenStream {
expand_derive(input, associations::derive_associations)
}

#[rustc_macro_derive(InferSchema)]
#[cfg_attr(not(test), rustc_macro_derive(InferSchema))]
#[cfg(any(feature = "sqlite", feature = "postgres"))]
pub fn derive_infer_schema(input: TokenStream) -> TokenStream {
let item = parse_macro_input(&input.to_string()).unwrap();
schema_inference::derive_infer_schema(item)
.to_string().parse().unwrap()
}

#[rustc_macro_derive(InferTableFromSchema)]
#[cfg_attr(not(test), rustc_macro_derive(InferTableFromSchema))]
#[cfg(any(feature = "sqlite", feature = "postgres"))]
pub fn derive_infer_table_from_schema(input: TokenStream) -> TokenStream {
let item = parse_macro_input(&input.to_string()).unwrap();
schema_inference::derive_infer_table_from_schema(item)
.to_string().parse().unwrap()
}

#[cfg_attr(not(test), rustc_macro_derive(EmbeddedMigrations))]
pub fn derive_embedded_migrations(input: TokenStream) -> TokenStream {
let item = parse_macro_input(&input.to_string()).unwrap();
migrations::derive_embedded_migrations(item)
.to_string().parse().unwrap()
}

fn expand_derive(input: TokenStream, f: fn(syn::MacroInput) -> quote::Tokens) -> TokenStream {
let mut item = parse_macro_input(&input.to_string()).unwrap();
let output = f(item.clone());
Expand Down
83 changes: 83 additions & 0 deletions diesel_codegen/src/migrations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
extern crate diesel;

use quote;
use syn;
use std::path::{Path, PathBuf};
use util::str_value_of_meta_item;
use diesel_codegen_shared::migrations::resolve_migrations_directory;

pub fn derive_embedded_migrations(input: syn::MacroInput) -> quote::Tokens {
let options = get_options_from_input(&input.attrs);
let dir = ::std::env::var("CARGO_MANIFEST_DIR").unwrap();
let callside = PathBuf::from(dir);
let migration_path = get_option(options, "migration_path")
.map(Path::new);
let migration_dir = t!(resolve_migrations_directory(callside.as_path(),
migration_path));
let migrations = migration_literals_from_path(migration_dir.as_path());
quote!(
mod embedded_migrations {
extern crate diesel;

use self::diesel::migrations::*;
use self::diesel::connection::SimpleConnection;

const ALL_MIGRATIONS: &'static [&'static Migration] = &[ #(migrations),*];

pub fn run<C: MigrationConnection>(conn: &C) -> Result<(), RunMigrationsError> {
run_with_output(conn, &mut ::std::io::sink())
}

pub fn run_with_output<C: MigrationConnection>(conn: &C, out: &mut ::std::io::Write)
-> Result<(), RunMigrationsError>
{
run_migrations(conn, ALL_MIGRATIONS.iter().map(|v| *v), out)
}
}
)
}


fn migration_literals_from_path(path: &Path) -> Vec<quote::Tokens> {
use self::diesel::migrations::migration_paths_in_directory;

t!(migration_paths_in_directory(&path)).into_iter()
.map(|e| migration_literal_from_path(&e.path()))
.collect()
}

fn migration_literal_from_path(path: &Path) -> quote::Tokens {
use self::diesel::migrations::version_from_path;

let version = t!(version_from_path(path));
let sql_file = path.join("up.sql");
let sql_file_path = sql_file.to_string_lossy();

quote!(&EmbeddedMigration{
version: #version,
up_sql: include_str!(#sql_file_path),
})
}

fn get_options_from_input(attrs: &[syn::Attribute]) -> Option<&[syn::MetaItem]> {
let option = attrs.iter().find(|a| a.name() == "options").map(|a| &a.value);
match option{
Some(&syn::MetaItem::List(_, ref options)) => Some(options),
_=> None
}
}

fn get_option<'a>(
options: Option<&'a [syn::MetaItem]>,
option_name: &str,
) -> Option<&'a str> {
match options.map(|o|{
o.iter().find(|a| a.name() == option_name)
.map(|a| str_value_of_meta_item(a, option_name))
}) {
Some(Some(r)) => Some(r),
_ => None,
}
}


22 changes: 0 additions & 22 deletions diesel_codegen_old/Cargo.toml

This file was deleted.

Loading

0 comments on commit 88c5f7a

Please sign in to comment.