New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better ergonomics for calling infer_schema when the database URL is not in the environment #689

Closed
mehcode opened this Issue Feb 12, 2017 · 2 comments

Comments

Projects
None yet
2 participants
@mehcode

mehcode commented Feb 12, 2017

I'm trying to use https://crates.io/crates/config (to centralize configuration) with Diesel. Diesel really wants me to use environment variables for everything.

In order to get a value out of config to use in infer_schema! I currently have something like the below in my build.rs. Any ideas to make this more ergonomic (or am I missing an easier way to do this)?

extern crate config;

mod config_ {
    // Include raw source for config module
    // Contains ::new method to create a new Config
    include!("src/config.rs");
}

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    // Get instance of active configuration
    let c = config_::new();

    // Write out 'schema.rs' to contain the active 'database.url'
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("schema.rs");
    let mut f = File::create(&dest_path).unwrap();

    f.write_all(format!(r#"
        infer_schema!("{}");
    "#, c.get_str("database.url").unwrap()).as_bytes()).unwrap();
}
@sgrif

This comment has been minimized.

Member

sgrif commented Feb 12, 2017

There's not really any way to make this easier or more ergonomic. In order to make infer_schema! work on stable via macros 1.1, we can only take string literals as arguments. Once we get Macros 1.1 for bang macros or macros 2.0, we will be able to go back to taking any arbitrary input that you want to give us, including one that is based on configuration files.

We have special handling for environment variables because it's a common pattern that is easy for us to support without forcing additional opinions on the application. For us to support some sort of configuration file today, we'd have to enforce a specific opinion about how configuration files should work for your application, which is not something I want to do in an ORM.

As an aside, is there a specific reason that using .env as a "configuration file lite" is something you don't want to do? Until we have another way to implement infer_schema! on stable which allows us to take arbitrary macro input, there's not much else we can do here. The only other option is to not use infer_schema! at all. We provide diesel print-schema which gives you the table! calls directly (though you'll end up needing to give that the database URL as well either through an environment variable or an argument)

@sgrif sgrif closed this Feb 12, 2017

@mehcode

This comment has been minimized.

mehcode commented Aug 11, 2017

Sorry it took me so long to come back to this.

As an aside, is there a specific reason that using .env as a "configuration file lite" is something you don't want to do?

In my projects I have (something like):

.
├── Cargo.lock
├── Cargo.toml
├── config
│   ├── default.toml
│   └── production.toml
├── migrations
└── src

Configuration flows in from config/default.toml, is overridden by config/${env}.toml, and finally, is overridden further by the environment.

When I add a .env file (which is intended to be sourced by dotenv) for consumption by the compiler and the CLI, I now have duplicated the development database URL in .env and config/default.toml.


Once we get Macros 1.1 for bang macros or macros 2.0 [...]

I can understand that. At least it's on the radar and that build.rs isn't that horrible in the meantime.

[...] (though you'll end up needing to give that the database URL as well either through an environment variable or an argument) [...]

Now here is where I'd like to make an actionable suggestion.

Would it be acceptable to expose a programmatic interface for running the CLI? It doesn't seem that coupled to the main.rs.

I'm thinking something along the lines of:

diesel_cli::run();
diesel_cli::run_with_args(&matches);

^ That would just do essentially what the main function does in diesel_cli/main.rs.

My vision for this is being able to mount the diesel cli so it's run like $ my-app diesel _. This way my-app can communicate whatever it needs to the CLI.

Another idea that could work is doing src/bin/diesel.rs and cargo run --bin diesel -- ... The official diesel CLI could even detect this pattern and use the "local" diesel instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment