-
Notifications
You must be signed in to change notification settings - Fork 271
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
257 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
--- | ||
title: "Announcing Atlas v0.9.0: SQL as a First-Class Citizen" | ||
authors: a8m | ||
tags: [migration, sql, erd] | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
For a long time, one of the most common feature requests we've been getting from our users is the ability to | ||
manage their desired "schema state" using SQL. This is understandable, using Atlas DDL (HCL) can feel unfamiliar to | ||
some users, especially those who have never worked with Terraform before. For this reason, we're excited to announce the | ||
release of Atlas v0.9.0, which now fully supports SQL. | ||
|
||
## Schema as Code (SaC) | ||
|
||
Atlas applies the common IaC concept of declarative resource management to database schemas. With Atlas, users do not | ||
need to plan schema changes themselves. Instead of figuring out the correct SQL statements to update their database | ||
schemas, users provide to Atlas the schema definition that describe their ***desired state*** and Atlas generates a | ||
migration plan to move from the ***current state*** to the desired state defined by the schema. | ||
|
||
Starting from v0.9.0, users can use SQL schema files (or a directory) containing `CREATE` and `ALTER` statements | ||
to describe their desired state. To demonstrate this, let's use this schema example with a single `users` table: | ||
|
||
```sql title="schema.sql" | ||
-- create table "users | ||
CREATE TABLE users( | ||
id int NOT NULL, | ||
name varchar(100) NULL, | ||
PRIMARY KEY(id) | ||
); | ||
``` | ||
|
||
Given this schema file, Atlas offers two workflows to update databases: | ||
|
||
- [Declarative](/declarative/apply): Similar to Terraform, Atlas compares the current state of the database schema with | ||
the desired state defined by the SQL schema, and generates a migration plan to reach that state. | ||
- [Versioned](/versioned/diff): Atlas compares the current state defined by the `migrations` directory to the | ||
desired state defined by the SQL schema, and writes a new migration script to the directory to update the database | ||
schema to the desired state. | ||
|
||
In this blog post, we'll focus on explaining how SQL schemas can be used with the declarative workflow. For the sake | ||
of simplicity, let's assume we have an empty database that we want to apply the schema above to: | ||
|
||
<Tabs | ||
defaultValue="mysql" | ||
values={[ | ||
{label: 'MySQL', value: 'mysql'}, | ||
{label: 'MariaDB', value: 'maria'}, | ||
{label: 'PostgreSQL', value: 'postgres'}, | ||
{label: 'SQLite', value: 'sqlite'}, | ||
]}> | ||
<TabItem value="mysql"> | ||
|
||
```shell | ||
atlas schema apply \ | ||
--url "mysql://root:pass@localhost:3306/example" \ | ||
--to "file://schema.sql" \ | ||
--dev-url "docker://mysql/8/example" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="maria"> | ||
|
||
```shell | ||
atlas schema apply \ | ||
--url "maria://root:pass@:3306/example" \ | ||
--to "file://schema.sql" \ | ||
--dev-url "docker://maria/latest/example" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="postgres"> | ||
|
||
```shell | ||
atlas schema apply \ | ||
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable" \ | ||
--to "file://schema.sql" \ | ||
--dev-url "docker://postgres/15" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="sqlite"> | ||
|
||
```shell | ||
atlas schema apply \ | ||
--url "sqlite://file.db" \ | ||
--to "file://schema.sql" \ | ||
--dev-url "sqlite://file?mode=memory" | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
:::info FLAGS | ||
- `--url` - the database URL to apply the schema to. | ||
- `--to` - URLs describe the desired state: SQL or HCL schema definition, or a database URL. | ||
- `--dev-url` - a URL to a [Dev Database](/concepts/dev-database) that will be used to compute the diff. | ||
::: | ||
|
||
Running the command above with the `--auto-approve` flag will apply the following changes: | ||
|
||
```sql | ||
-- Planned Changes: | ||
-- Create "users" table | ||
CREATE TABLE `users` (`id` int NOT NULL, `name` varchar NULL, PRIMARY KEY (`id`)); | ||
``` | ||
|
||
Hooray! We have successfully created the `users` table defined in our schema file. Let's inspect our database and ensure | ||
its schema was actually updated by the command above: | ||
|
||
|
||
<Tabs | ||
defaultValue="mysql" | ||
values={[ | ||
{label: 'MySQL', value: 'mysql'}, | ||
{label: 'MariaDB', value: 'maria'}, | ||
{label: 'PostgreSQL', value: 'postgres'}, | ||
{label: 'SQLite', value: 'sqlite'}, | ||
]}> | ||
<TabItem value="mysql"> | ||
|
||
```shell | ||
atlas schema inspect \ | ||
--url "mysql://root:pass@localhost:3306/example" \ | ||
--log "{{ sql . }}" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="maria"> | ||
|
||
```shell | ||
atlas schema inspect \ | ||
--url "maria://root:pass@:3306/example" \ | ||
--log "{{ sql . }}" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="postgres"> | ||
|
||
```shell | ||
atlas schema inspect \ | ||
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable" \ | ||
--log "{{ sql . }}" | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="sqlite"> | ||
|
||
```shell | ||
atlas schema inspect \ | ||
--url "sqlite://file.db" \ | ||
--log "{{ sql . }}" | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
Excellent! As you can see, our database schema has been updated: | ||
|
||
```sql | ||
-- create "users" table | ||
CREATE TABLE `users` (`id` int NOT NULL, `name` varchar NULL, PRIMARY KEY (`id`)); | ||
``` | ||
|
||
Now let's make our schema more interesting by adding a column to the `users` table and creating a `blog_posts` table | ||
with a foreign key that references `users`: | ||
|
||
```sql title="schema.sql" {5,10-17} | ||
-- create table "users | ||
CREATE TABLE users( | ||
id int NOT NULL, | ||
name varchar(100) NULL, | ||
email varchar(50) NULL, | ||
PRIMARY KEY(id) | ||
); | ||
|
||
-- create table "blog_posts" | ||
CREATE TABLE blog_posts( | ||
id int NOT NULL, | ||
title varchar(100) NULL, | ||
body text NULL, | ||
author_id int NULL, | ||
PRIMARY KEY(id), | ||
CONSTRAINT author_fk FOREIGN KEY(author_id) REFERENCES users(id) | ||
); | ||
``` | ||
|
||
Next, executing `atlas schema apply` again will update the database schema with the following changes: | ||
|
||
```sql title="atlas schema apply" | ||
-- Planned Changes: | ||
-- Add column "email" to table: "users" | ||
ALTER TABLE `users` ADD COLUMN `email` varchar NULL; | ||
-- Create "blog_posts" table | ||
CREATE TABLE `blog_posts` (`title` varchar NULL, `body` text NULL, `author_id` int NULL, `id` int NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `author_fk` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION); | ||
``` | ||
|
||
Boom! Atlas automatically calculates the difference between the ***current state*** of our database and the ***desired state*** | ||
defined by our schema file, and generates the necessary changes to migrate the database to the new state. We don't need to | ||
specify each individual migration – we simply tell Atlas what state we want the database to be in, and it handles the rest. | ||
|
||
To see a full description of this generated migration plan, check out this diagram example in [Atlas public playground](https://gh.ariga.cloud/explore/f95ffc45...20d5152c): | ||
|
||
#### Diff ERD | ||
|
||
[![](https://atlasgo.io/uploads/images/diff-erd.png)](https://gh.ariga.cloud/explore/f95ffc45...20d5152c) | ||
|
||
#### Diff SQL | ||
|
||
[![](https://atlasgo.io/uploads/images/diff-sql.png)](https://gh.ariga.cloud/explore/f95ffc45...20d5152c) | ||
|
||
## Atlas Playground | ||
|
||
As part of this version, we have released the [Atlas playground](https://gh.ariga.cloud/explore) where users can visualize their | ||
database schemas in an interactive way. Simply provide an SQL or HCL schema, or import one from an existing database, | ||
and in return get an ERD visualizing their entire data model. | ||
|
||
Users can also compare between two schemas with the *Schema Diff* button, and get the SQL statements necessary to | ||
migrate from one schema to the other - [give it try!](https://gh.ariga.cloud/explore/01d2aeb1) | ||
|
||
<p style={{textAlign: "center"}}><a href="https://gh.ariga.cloud/explore/01d2aeb1"> | ||
<img src="https://atlasgo.io/uploads/images/diff-erd-short.gif" alt="Blog ERD"/> | ||
</a></p> | ||
|
||
A big thanks to [@solomonme](https://github.com/solomonme), [@ronenlu](https://github.com/ronenlu) and [@masseelch](https://github.com/masseelch) | ||
for contributing this feature to Atlas! | ||
|
||
## Schema Loaders | ||
|
||
What's next? In the near future, we plan to add an infrastructure for loading schemas from external sources. This will | ||
enable ORM maintainers to integrate with Atlas and provide their schema definitions as Atlas schemas. As as result, they | ||
can utilize the Atlas engine to diff schemas, plan and lint migrations, execute them on the databases, and more. | ||
|
||
The first ORM to integrate with Atlas will be [Ent](https://entgo.io/). Using this integration, Ent users will be able | ||
to generate Atlas schemas or migrations for their Ent projects with a single command: | ||
|
||
```shell {3} | ||
atlas migrate diff create_users \ | ||
--dir "file://migrations" \ | ||
--to "ent://path/to/schema" \ | ||
--dev-url "docker://<driver-name>" | ||
``` | ||
|
||
Would you like to see other ORMs integrated with Atlas? Please, join our [Discord server](https://discord.gg/zZ6sWVg6NT) | ||
and let me know. | ||
|
||
## What next? | ||
|
||
Have questions or feedback? Feel free to reach out [on our Discord server](https://discord.gg/zZ6sWVg6NT). |