Repository: ariga/atlas
Pull request #1451 (2023-02-08 10:34:52)

doc/md/declarative: add doc for declarative migrations with single schemas (HCL)


Patch:
diff --git a/doc/md/declarative/declarative-hcl.mdx b/doc/md/declarative/declarative-hcl.mdx
new file mode 100644
index 00000000..3b20d473
--- /dev/null
+++ b/doc/md/declarative/declarative-hcl.mdx
@@ -0,0 +1,250 @@
+---
+id: declarative-hcl-singleschema
+title: Getting started with HCL declarative migrations for a MySQL schema
+slug: /declarative/declarative-hcl
+---
+
+import InstallationInstructions from '../components/_installation_instructions.mdx'
+
+### Introduction
+
+Atlas makes it easy to manage your database using the declarative migrations workflow. Declarative migrations focus on describing the desired state of the database and allow the migration engine to plan and execute the necessary actions to reach that state.
+
+In this quickstart guide, we will go through the three essential steps for using Atlas to manage your database schema: inspecting your database, authoring the desired changes, and applying those changes.
+
+### Installing Atlas
+
+<InstallationInstructions />
+
+### Warming up
+To demonstrate the examples in the article, let's start a docker container with an `example` database and create a table in it.
+
+Use the following command to run a MySQL Docker container
+
+```console
+docker run --name atlas-demo -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=example -p 3306:3306 -d mysql:latest
+```
+
+Once the container is running, you can connect to the MySQL server using the statements below:
+
+```console
+docker exec -it atlas-demo mysql -ppass --database=example
+```
+
+Once you're connected, you can create a table in it by running the following command:
+
+```sql
+CREATE TABLE customers (
+    id INT PRIMARY KEY AUTO_INCREMENT,
+    first_name VARCHAR(255) NOT NULL,
+    last_name VARCHAR(255) NOT NULL
+);
+```
+
+## Step 1: Inspecting the database
+
+Before planning any changes to your database, it can be useful to know what your database schema looks like. To do this, you can use the `atlas schema inspect` command to inspect your database. This command generates a file that represents your database schema, which can be used as a starting point for making changes.
+
+### Usage:
+```
+atlas schema inspect [flags]
+```
+
+### Example:
+
+The following command will inspect the current state of the schema `example` and store it in a file named `schema.hcl`
+
+```console
+atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
+```
+
+```hcl title="schema.hcl"
+schema "example" {}
+
+table "customers" {
+  schema = schema.example
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+  column "first_name" {
+    null = false
+    type = varchar(255)
+  }
+  column "last_name" {
+    null = false
+    type = varchar(255)
+  }
+  primary_key {
+    columns = [column.id]
+  }
+}
+```
+:::info
+To learn more about inspecting schema with Atlas in variety of use cases, visit the documentation [here](https://atlasgo.io/declarative/inspect)
+:::
+
+## Step 2: Planning a change
+
+Once you have inspected your database, the next step is to plan a change. This is done by modifying the HCL file in a way that it defines the desired state of your schema. The file should include the changes you want to make to your database, such as creating tables, columns, or indexes.
+
+### Example:
+
+Let’s add the following table definition to the HCL schema file that we previously created with the `atlas schema inspect` command:
+
+```hcl title="schema.hcl" {23-45}
+schema "example" {}
+
+table "customers" {
+  schema = schema.example
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+  column "first_name" {
+    null = false
+    type = varchar(255)
+  }
+  column "last_name" {
+    null = false
+    type = varchar(255)
+  }
+  primary_key {
+    columns = [column.id]
+  }
+}
+
+table "orders" {
+  schema = schema.example
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+  column "customer_id" {
+    null = false
+    type = int
+  }
+  column "order_date" {
+    null = false
+    type = date
+  }
+  primary_key {
+    columns = [column.id]
+  }
+  foreign_key "customer_id_fk" {
+    columns     = [column.customer_id]
+    ref_columns = [table.customers.column.id]
+  }
+}
+```
+
+## Step 3: Applying the change
+
+The final step is to apply the change to your database. To do this, simply run the `atlas schema apply` command. This command will compare the current state of your database to the desired state defined in your HCL file and make the necessary changes.
+
+### Usage:
+
+```console
+atlas schema apply [flags]
+```
+
+### Example:
+
+Let’s apply the changes we created in Step 2 using the following command:
+
+```console
+atlas schema apply \
+  --url "mysql://root:pass@localhost:3306/example" \
+  --to "file://schema.hcl"
+```
+
+```console
+-- Planned Changes:
+-- Create "orders" table
+CREATE TABLE `example`.`orders` (`id` int NOT NULL AUTO_INCREMENT, `customer_id` int NOT NULL, `order_date` date NOT NULL, PRIMARY KEY (`id`), INDEX `customer_id_fk` (`customer_id`), CONSTRAINT `customer_id_fk` FOREIGN KEY (`customer_id`) REFERENCES `example`.`customers` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
+Use the arrow keys to navigate: ↓ ↑ → ← 
+? Are you sure?: 
+  ▸ Apply
+    Abort
+```
+
+Selecting `Apply` will apply the changes to the database.
+
+You can inspect the latest state of the database again and verify that the changes have been applied by re-running the `atlas schema inspect` command:
+
+```console
+atlas schema inspect -u "mysql://root:pass@localhost:3306/example"
+```
+```hcl
+table "customers" {
+  schema = schema.example
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+  column "first_name" {
+    null = false
+    type = varchar(255)
+  }
+  column "last_name" {
+    null = false
+    type = varchar(255)
+  }
+  primary_key {
+    columns = [column.id]
+  }
+}
+table "orders" {
+  schema = schema.example
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+  column "customer_id" {
+    null = false
+    type = int
+  }
+  column "order_date" {
+    null = false
+    type = date
+  }
+  primary_key {
+    columns = [column.id]
+  }
+  foreign_key "orders_ibfk_1" {
+    columns     = [column.customer_id]
+    ref_columns = [table.customers.column.id]
+    on_update   = NO_ACTION
+    on_delete   = NO_ACTION
+  }
+  index "orders_ibfk_1" {
+    columns = [column.customer_id]
+  }
+}
+schema "example" {
+  charset = "utf8mb4"
+  collate = "utf8mb4_0900_ai_ci"
+}
+```
+Great! Our changes have been successfully applied to the `example` schema.
+
+### Conclusion
+
+By following the steps above, you can inspect the current state of the database, make changes to the schema definition file and apply those changes to the database with confidence.
+
+The declarative migration is a flexible way to manage your database schema. It allows you to define your desired state in a simple, human-readable language, and then automatically apply those changes to your database. This can save you time and effort, and also reduce the risk of errors or inconsistencies in your database schema.
+
+:::info
+Atlas supports both Declarative and Versioned workflows for managing database schemas. The choice between the two depends on your requirements. To understand the difference and choose the best option for you, visit the documentation on Declarative vs Versioned workflow [here](https://atlasgo.io/concepts/declarative-vs-versioned).
+:::
+
+## Need More Help?​
+
+[Join the Ariga Discord Server](https://discord.com/invite/zZ6sWVg6NT) for early access to features and the ability to provide exclusive feedback that improves your Database Management Tooling. 
+
+[Sign up](https://atlasnewsletter.substack.com/) to our newsletter to stay up to date about [Atlas](https://atlasgo.io), our OSS database schema management tool, and our cloud platform [Atlas Cloud](https://atlasgo.cloud).
diff --git a/sql/sqlite/convert.go b/sql/sqlite/convert.go
index 18720237..07394e6e 100644
--- a/sql/sqlite/convert.go
+++ b/sql/sqlite/convert.go
@@ -63,7 +63,7 @@ func ParseType(c string) (schema.Type, error) {
 		return &schema.BoolType{T: t}, nil
 	case "blob":
 		return &schema.BinaryType{T: t}, nil
-	case "int2", "int8", "int", "integer", "tinyint", "smallint", "mediumint", "bigint", "unsigned big int":
+	case "int2", "int8", "int", "uint64", "integer", "tinyint", "smallint", "mediumint", "bigint", "unsigned big int":
 		// All integer types have the same "type affinity".
 		return &schema.IntegerType{T: t}, nil
 	case "real", "double", "double precision", "float":
diff --git a/sql/sqlite/sqlspec.go b/sql/sqlite/sqlspec.go
index 79ef3dab..3968f5c7 100644
--- a/sql/sqlite/sqlspec.go
+++ b/sql/sqlite/sqlspec.go
@@ -177,6 +177,7 @@ var TypeRegistry = schemahcl.NewRegistry(
 		schemahcl.AliasTypeSpec("unsigned_big_int", "unsigned big int", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
 		schemahcl.NewTypeSpec("int2", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
 		schemahcl.NewTypeSpec("int8", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
+		schemahcl.NewTypeSpec("uint64", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
 		schemahcl.NewTypeSpec("double", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
 		schemahcl.AliasTypeSpec("double_precision", "double precision", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),
 		schemahcl.NewTypeSpec("float", schemahcl.WithAttributes(schemahcl.SizeTypeAttr(false))),


Test patch:
diff --git a/internal/integration/testdata/sqlite/cli-inspect.txt b/internal/integration/testdata/sqlite/cli-inspect.txt
index 7a00c4d2..9314d8c4 100644
--- a/internal/integration/testdata/sqlite/cli-inspect.txt
+++ b/internal/integration/testdata/sqlite/cli-inspect.txt
@@ -44,6 +44,10 @@ table "users" {
     null = false
     type = int
   }
+  column "ac" {
+    null = false
+    type = uint64
+  }
 }
 schema "main" {
 }
diff --git a/sql/sqlite/sqlspec_test.go b/sql/sqlite/sqlspec_test.go
index 9e021eb4..8c293189 100644
--- a/sql/sqlite/sqlspec_test.go
+++ b/sql/sqlite/sqlspec_test.go
@@ -312,6 +312,10 @@ func TestTypes(t *testing.T) {
 			typeExpr: "int8(10)",
 			expected: &schema.IntegerType{T: "int8"},
 		},
+		{
+			typeExpr: "uint64",
+			expected: &schema.IntegerType{T: "uint64"},
+		},
 		{
 			typeExpr: "real",
 			expected: &schema.FloatType{T: "real"},