Sunday, December 10, 2017

Diesel: How To have struct fields named differently than their columns

Diesel is very good at generating code that reduces the amount of boilerplate you have to write. You can explicitly ask something like
.filter(email.like(""))
and it will know how to filter based on the 'email' column, and how to populate a struct based on this.

For some reason, this falls apart when you're trying to derive the  Insertable trait.

The solution is hidden away in the API documentation, which is currently at this link.

The Solution
So, you just have to set up mappings between your struct fields and your database column in order to insert your struct as a record. Here's an example:

table:
Create Table User(EmailAddress text primary key not null, Name text not null)

struct:

#[derive(Queryable, Insertable)]
#[table_name="User"]
pub struct User {
   
    #[column_name(EmailAddress)]
    pub address: String,

    #[column_name(Name)]
    pub name: String
}

There aren't supposed to be quotes around the column names, as it's using the diesel-generated helper structures. As such, you have to make sure that your schema is imported for this to properly work.

Wednesday, November 22, 2017

Rust: Setting up a Sqlite Database with diesel

How does the database stack in Rust work?
For a long while, the database ecosystem in Rust was severely lacking. Thankfully, once Rust Stable 1.0.0 was released, the ecosystem has seen nothing but improvement and growth. Now, most users wind up using diesel, a query-builder that helps immensely with designing your data access layer.

What you need before you start
 You should have sqlite3 installed on your system of choice, as well as the latest version of cargo and rustc.

Step 1: Set up your project
As with any Rust project, simply running cargo init {project} will initialize a rust project with the file structure that cargo can understand. This will generate your Cargo.toml file, where we'll tell it what it needs to start using diesel with sqlite3.
 
Step 2: Set up your project's dependencies
In order to use diesel, you'll need the diesel libraries. It's also highly recommended that you include something called dotenv. This will let you specify what your database is per-project, which you really want. Otherwise, your entire system will only find one database. Or, alternatively, you will need to manually specify a database with every session.

Add these lines to the [dependencies] section in your Cargo.toml file:

diesel = { version = "0.16.0", features = ["sqlite"] }
diesel_codegen = { version = "0.16.0", features = ["sqlite"] }
dotenv = "0.9.0"


Now, you can configure the URL of your database. Create a new file in the same directory as your Cargo.toml file simply called .env. This will be a hidden file, so you may need to enable those to see it.

Make the text of this .env file simply 

DATABASE_URL={database}

So, if you want a sqlite3 database called test.sqlite3, your .env would look like:

DATABASE_URL=test.sqlite3 
 
Step 3: Initialize your database
 Much of the work you'll be doing is done through a command line tool, called simply diesel. First, you need to install this utility globally, with
cargo install diesel --no-default-features --features sqlite

On Linux, this will place the executable in your $HOME/.cargo/bin/ folder. You may need to add this folder to your $PATH in order to use diesel.

To create your database, go to the directory where your Cargo.toml is located and run diesel setup. This will initialize a blank sqlite3 database.
  
Step 4: Start designing your schema 
In order to set up an initial schema, and begin using your database, you have to initalize a migration. To do this, run diesel migration generate {migration-name}.

For this first migration, I tend to just do

diesel migration generate initialize

This will generate a new directory, with today's date and time, that contains an up.sql and down.sql. As the official guide states, down.sql simply should undo any schema changes you make in up.sql

You're all set!
I wrote this guide because I ran into a few pitfalls following the official guide. However, the official guide is absolutely fantastic, and describes everything that I summarized here in a clearer, more complete way. I recommend that you go and check it out at

http://diesel.rs/guides/getting-started/    

Sunday, November 12, 2017

Rust: How to use the latest version of a Cargo Crate

Why Cargo is so brilliant
Cargo is a fantastic tool. From the get-go, it's gotten a lot of things right that package managers like npm and nuget still stumble over. The competitors to these tools, yarn and paket address the issues that, thankfully, Cargo has already solved.

You know what npm got right, though? It's dead simple to hook a package up. Do you want to use react? You can just type npm install --save react, and it will find the latest version of React, and add it to the packages.json file. Cargo, too, can be abused to have this functionality.

Warning: You really shouldn't do this...
By explicitly listing versions in your Cargo.toml file, you know for a fact that a future release of the package won't break your project. Furthermore, you know for a fact that the different dependencies that you're relying on play nicely together.

One of the goals of dev-ops is minimizing risk. Having an explicit definition of the packages that could break your project is one of the most important ways to do this.

With that said...
A quick spiel on Semver
Semver, the syntax for identifying the version of the package you want to use, is a widely upheld standard. You can read the full semver guidelines to grok exactly what's happening when you type a version in. Cargo use's a Rust semver library (which can be found here) to parse its dependencies version section.

By abusing the Greater-Than functionality, we can trick Cargo to installing the latest version of a package.

Example: Installing the latest Serde
This line in your Cargo.toml file:

serde = ">0.0.0"

is all you need for Cargo to install the latest version of Serde. This can be used for any package that you don't care about the version for. Be careful with this trick. There's a reason Cargo doesn't technically support this type of workflow outside of this hack.

How To: Remove part of i3's bar with i3status

The Problem
i3bar is perfectly simple. It's not this gaudy, in-your-face information supernova that Windows has been iterating on for the last ~20 years. It tells you just what you need to know: space left, internet speed, CPU load, and the time. But... what if you don't care about your internet speed? Or the time?

Thankfully, removing it is dead simple.

i3status.conf
If you're using the default i3status for your i3bar, the fix is simple. A configuration file in your home directory overrides the default in /etc/i3status.conf. (placing one in $HOME/.config/i3status/config will override the one in your home directory).

Setting the Overrides 
So, you have two options. You can make a NEW file in either of those locations, copying the existing data over. Or, you can edit /etc/i3status.conf directly as root (not recommended).

Using the documentation in man i3status and your existing file (/etc/i3status.conf), you should be able to find the commands you want. Then, make sure that only the commands you care about are in the order variable.

For instance, by default, my order looked like this:

order += "disk /"
order += "ethernet _first_"
order += "load"
order += "tztime local"
Since I don't care about my ethernet, I struck it. Resulting in this:

order += "disk /"
order += "load"
order += "tztime local"

Rust: Returning JSON with Rocket

Preamble
JSON is one of the technologies that, while very simple at its core, has had a profound impact on the technical landscape. Most modern public API's rely on JSON to transport information between application layers. It's become essential from everything ranging from Web API's, compiler technologies, and even data storage.

With that said, it's essential for an up-and-coming web tech stack like Rust and Rocket to support it. And support it they do.

Step 1: Install Dependencies
For some reason, the official Rocket documentation hides the fact that you need dependencies outside of rocket_codegen and rocket in order to return JSON.

You need to have all of the following lines in your Cargo.toml file:

rocket = "0.3.3"
rocket_codegen = "0.3.3"
rocket_contrib = "0.3.3"
Obviously, these versions will change over time. Without these dependencies, you may find yourself with errors such as:

"Cannot find macro json!", "Value cannot be found", etc. when following Rocket's documentation.

Step 2: Start returning JSON
Now, the easy part. I'm going to post the single most rudimentary example of a JSON return ever. In real web projects, you'll want to use serde and serde_derive to turn your data-transfer objects / models into a consistent JSON format. For now, we'll use the json! macro and Json struct to hard-return a value on the root route:

#[get("/")]fn index() -> Json<Value> {
    Json(json!({"value": 5}))
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();}

Sunday, October 29, 2017

Rust: How To Fix "no default toolchain configured" and "the following required arguments were not provided: toolchain"

The Problem
What's happening here, is that you've installed rust utilities via rustup: cargo, rustc, etc. The problem is, these utilities cannot find the default rust 'toolchain', as it has not been configured yet.

The Fix
This is a very simple fix. The following command:

rustup default stable

In this case, you want to change stable to be whatever release channel you're on. For nightly rust, this would switch to 

 rustup default nightly


Saturday, October 7, 2017

[Fix]: No Audio in Linux / Videos Don't Play

The Problem
There exists an especially frustrating problem on some linux distributions where audio will simply not play. The lack of audio playing can mean that you're also not able to watch videos, even completely without audio! Most recently, I installed Ubuntu 17.04 to find that I was unable to listen to music or even watch Youtube videos with subtitles. That's untenable, and a complete deal-breaker for most people (for obvious reason).

The Explanation
So, what's really happening here is that your user isn't in the audio group. Because they're not in the audio group, videos which contain audio (i.e all video file formats) are simply not allowed to play! Why users aren't de facto members of the audio group, especially on Linux, is completely lost on me. But, it's enough information to fix the problem thankfully. 

(Optional) A Quick Rundown on Groups
For the uninitiated; Linux has two essential components of its security system: groups and users. Users are added to groups to give them certain privileges. So, since your user is NOT a member of the audio group, you cannot play audio.

The Fix
The fix for this couldn't be easier. You need to run the following command:

sudo usermod -a -G groupName userName
Then, we're already half way done! You are now a member of the audio group. 
To apply this fix, you *need* to shut down and power back up
For me, nothing actually applied this change other than a full shutdown / restart cycle. Even rebooting didn't actually do it for me, strangely enough. That goes against all of my intuition as an avid computer user and programmer. I can't explain it.
Once you've reboot, you should then be able to run the following command:
alsamixer
Then, hover over the columns which read 'MM' and hit 'm' to unmute them. Raise their volume to 100%. Your desktop environment will control the actual volume you here, but you don't want the underlying sound system to artificially lower your volume.
The Last Step
The final thing you have to do is to run the following command:
pavucontrol
Then, from here, set up whatever audio device you'll be using. In my case, with headphones plugged into the audio jack it wound up being 'Line Out'. Under the configuration tab, I needed to select Audio Stereo Duplex for it to work. I'm also unsure why the Audio Stereo Duplex configuration works, but I know it does.
You're Done!
After all of this, you should have working audio. As you can tell, the rumor that Linux audio can be a headache is proven to be true. Videos should already be working. If you are still having trouble with it, leave a comment below and I'll do my best to help out.

Tuesday, March 7, 2017

[How To]: Not commit when a string is present in git

The Use Case
Howdy! So, I ran into an interesting problem this week. In order to test something, I had to make a change to code that should NEVER be commit... then, I commit it. D'oh!

If you want to protect yourself from something similar, or prevent data leakage, read on.

The Setup
When you clone or initialize a git project, git creates a "./.git" folder for you. This is where it tracks information about the repository, and stores some git metadata and logs.


Another thing this folder contains are "hooks", which are run at some point during the git workflow. For instance, if we had a "pre-push" hook, it would run before the push goes up to the remote.

So, what can we do with these hooks? Anything that BASH lets us. The most common use case for hooks is stopping a commit if something isn't right with the project, which is what we'll be doing in our case. However, you could do things like:


  • Print out the total number of lines changed
  • Check for a string and just give warnings (i,e mispellings, swear words)
  • Queue a local or remote backup
  • Package the project
Really, anything.

Protecting Ourselves
We would like to not commit if a string is present in the file. Imagine if we wanted to search for //[DANGER]. The presence of [DANGER] in any tracked file would stop the commit, so you could remember to go back and change the reason for it being there.

To do this, open the pre-commit.sample file and save it as pre-commit (with no extension). If there isn't a sample file, simply make the pre-commit file.

Before we write any code, let's look at what we want:

  • If a string is present ANYWHERE in the directory, fail
Alternatively, in large code bases, we want:
  • Search the diff for newly added instances of the string
Since searching through every file is going to take too long to do on every commit.

The Steps

Make the File
You should now have a file called ./.git/hooks/pre-commit. You make need to mark the pre-commit file as executable with chmod + x pre-commit.

Add this code to the file


printf "[Check]: Searching for commit mollyguard: '%s'..." "$breakingString"
sleep 1
#                                                                       VVVVVVV YOUR REGEX RIGHT THERE
if [ $(git diff --word-diff --cached --diff-filter=ACUM -U0 | grep -E "+*\[DANGER\]" | wc -l) -gt 0 ]
then 
printf "\n"
cat <<\EOF
Error: Trying to commit a tree that contains uncommitable changes 

Search the projects for $breakingString and figure out why the comment is there
EOF
exit 1;
fi

printf "Good!\n"


What this code is doing: 
  • Look at the last diff
  • Search the diff for "+{string}" (because + means it was ADDED, not removed in the last commit)
  • Count the lines
If the lines are greater than 0, and instance was found, so we shouldn't commit this branch.

Of course, this is searching just the latest commit, because searching a large software project is going to take a while. If you're working on a smaller project (or on a very fast machine), you can replace the if statement with simply

if [ $(grep -R "\[DANGER\]"../../  | wc- l) > 0 ]


Sunday, March 5, 2017

.NET - "%5C" Showing Up on URLs

Are you a developer, who is accepting a file or some string of text and putting it into a cloud? Are you, also, per chance, retrieving its URL, and notcing this pesky "%5C popping up in our URLs? Well, I know recently I was. It was a pretty strange, out of the blue error with an interesting cause. Here are some details for you:

What Causes This?
The actual causes of this problem are numerous. The bottom line is, '%5C' in a URL means that the backslash '\' got encoded in the URL. Somewhere along the way, either unintentionally or on purpose, a string containing one wound up in the encoding step.

The culprit for many users is using .NET's Path utility for trying to parse URLs. Here's an example:

Let's look at expectation vs Reality

Code: Path.GetDirectoryName("I/want/to/upload/to/this/place")
Expected: "I/want/to/upload/to/this/"
Actual: "I\want\to\upload\to\this"

This is because Path uses a field called Path.DirectorySeperatorChar, which on Windows is '\'... A bit backwards that Path can READ forward slashes as directory names, yet only output backslashes in the return value.

How Do I Fix This?
There are plenty of good solutions to fix this. However, with so many different causes to the problem, it's hard to say exactly.

To Fix it in a simple string
It's possible that all you need to do is Path.GetDirectoryName(your_string).Replace(Path.DirectorySeperatorChar, Path.AltDirectorySeperatorChar), and you're good to go.

Hopefully this shed some light on what the problem may be in your case. Hopefully, moving forward, Microsoft is not afraid to add a .NET feature like PathFlags or something so that this doesn't crop up as much as it currently does.