Enter your email below to watch this video
Mastering Postgres is such a crisp way to learn this subject. With today’s AI tools writing many of the queries via autocomplete it’s vital to have this knowledge to ensure you know what’s actually happening under the hood. My app’s performance improved overnight after learning more about indexing. Aaron’s excitement for the subject makes it really fun to learn whether I’m next to my code editor or on a treadmill run.Peter Ramsing
Shorten dev cycles with branching and zero-downtime schema migrations.
If you thought CHECK constraints were cool, which you probably did because they are objectively awesome, you're going to love domains. When we looked at CHECK constraints in a previous video, you declare your column name, your data type, then your constraint.
A domain wraps up the data type the constraint into one custom name. It's kind of like a custom type except it relies on an underlying type it is a combination of a type some constraints. Let me show you. Here's a simple little example of a table that holds addresses. We have street, city, postal code. We're going to make this applicable to just the United States of America. Here in the U.S. You can have a postal code that is five characters long, or it has this other dash four character long suffix. This is kind of a broad area, this is a more specific area within that broad area. Interestingly, it can be, it can have a leading zero. You don't want to declare your postal code as numeric or integer because you might lose that leading zero. Also, it wouldn't support this dash, that's no good.
What we're going to do is we're going to start with text then are we going to add a CHECK constraint? We could absolutely do that, what I want to show you is that we can do something that's a little bit more, I think, useful in this example, at least it's a good tool for you to have in your toolbox. We are going to use this new thing called domain. We are going to create a domain called U.S. Postal Code. This only works in the United States. Other countries have different formats, you could write one for that.
The thing about domains is it combines the data type the text or the CHECK constraint. We're going to say as text, then we're going to say constraint, I'm just going to give it a name of format. We'll say that it must meet this constraint named format. Then sorry about the chaotic capitalization. Then we're going to do CHECK, then what we want to do here is we want to say that the value matches a certain regex. Instead of saying the column name, because we don't actually know what the column name is, right? This is a standalone entity, a standalone object. Instead we're just going to use VALUE then we're going to match this regex, we're going to say the start of the string then five digits, well a digit, five times that matches the first example that I showed you, that one right there.
We also want to match this other example, which would be the dash four. We can also say, or VALUE tilde. I think that's tilde is that, that's called a tilde, right? That's the regex operator or VALUE matches the regex of let's go grab this guy. We'll say, let's throw an end of string on here as well. It's going to be exactly five digits, or in this case it's going to be five digits followed by exactly four digits with end of string here. Now we can create this domain. One of the interesting things about domains, you can reuse them across multiple columns.
You can reuse them across multiple tables. Unlike a CHECK constraint, where remember, we wrote the price constraint twice, that the price had to be greater than zero the discounted price had to be greater than zero. With this, we now have this, we have this kinda like domain specific type that in fact is an underlying type paired with just a normal CHECK constraint. Let me show you. I'm going to go ahead run this. If we run that, we have just created the domain, which now means we are allowed to use it down here, U.S. Postal code, you can also, you can also optionally append in this example a NOT NULL. Now if we run that, we have created the table let's see if anything I've been telling you is true, insert into domain example. We'll do street, city, postal, just we're clear, values of street, could be main, city could be Dallas, great city, postal.
Let's do some postal work here. Postal 7432 should fail. Yep, validates, this is nice, look at this. It gives you the domain, U.S. Postal code. Because we named it, you could have multiple up here, because we named this one format, it failed the format, which is nice. If we throw a zero on there, we're good. Then if we do just three characters, we're bad. If we throw a nine in there, we're good. In fact, if we throw an alpha in there, it must be a digit. It failed the format as well.
There you go. Now domains are awesome. As you can see, this makes it very clear, very easy to reason about when Postgres is operating on this postal column, which is this U.S. Postal code domain. It's actually operating on the text column. You haven't really created a custom data type. You've just wrapped up a regular data type a constraint. If this were an integer under the hood, all the operations would still work. Nothing would be wonky there. One thing about domains as compared to CHECK constraints, when you put a table level CHECK constraint on a table, it can reference multiple columns. A domain can only reference a single column. That's a little bit of a difference.
You can alter a domain that's really nice. Whereas you would have to drop recreate a constraint. You can alter a domain, in fact you can say, hey, I'm going to alter this domain don't validate this new, this new CHECK constraint, if you're adding a CHECK constraint. Don't validate this against the old columns, validate it against new rows that are coming in. That might be a good way to gradually roll out a new constraint. If your, for example, your U.S. Postal code rule changes, you can alter the domain you can leave the old data in there until the time when, until the time when you can update it to be valid. Then you can alter the domain again enforce all the new rules once you're guaranteed that it's valid.
Domains are very cool. I like them. I like them as a way to encapsulate the type the CHECK constraint, I like them as a way of communicating to other members of the team or other developers or something like that. I like them as a way of reusing CHECK constraints. If you have, if you have a price or you have an age or a birthday or a postal code, or God forbid you're validating email addresses with regex, don't do that. You can share those domains across multiple tables keep that logic very consistent. Whereas a CHECK constraint, you would have to rewrite it every single time.