Repository: ariga/atlas
Pull request #2807 (2024-05-27 11:52:12)

doc/md/guides/eval: new evaluation guide infra


Patch:
diff --git a/cmd/atlas/go.mod b/cmd/atlas/go.mod
index beeab7b3..d227a83c 100644
--- a/cmd/atlas/go.mod
+++ b/cmd/atlas/go.mod
@@ -24,7 +24,7 @@ require (
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.8.4
 	github.com/vektah/gqlparser/v2 v2.5.1
-	github.com/zclconf/go-cty v1.8.0
+	github.com/zclconf/go-cty v1.14.4
 	gocloud.dev v0.36.0
 	golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
 	golang.org/x/mod v0.15.0
@@ -41,6 +41,7 @@ require (
 	github.com/agext/levenshtein v1.2.1 // indirect
 	github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
 	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
 	github.com/aws/aws-sdk-go v1.49.0 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.24.0 // indirect
 	github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect
diff --git a/cmd/atlas/go.sum b/cmd/atlas/go.sum
index 3f06b884..6f5d4318 100644
--- a/cmd/atlas/go.sum
+++ b/cmd/atlas/go.sum
@@ -31,6 +31,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
 github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
 github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY=
 github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
 github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=
@@ -125,10 +127,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -255,11 +255,9 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4=
 github.com/vektah/gqlparser/v2 v2.5.1/go.mod h1:mPgqFBu/woKTVYWyNk8cO3kh4S/f4aRFZrvOnp3hmCs=
-github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
-github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
-github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
+github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
+github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
@@ -291,9 +289,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -330,7 +326,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
@@ -354,7 +349,6 @@ google.golang.org/api v0.151.0 h1:FhfXLO/NFdJIzQtCqjpysWwqKk8AzGWBUhMIx67cVDU=
 google.golang.org/api v0.151.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
 google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
diff --git a/cmd/atlas/internal/cmdext/reader.go b/cmd/atlas/internal/cmdext/reader.go
index 1cffb0e0..49a2fedd 100644
--- a/cmd/atlas/internal/cmdext/reader.go
+++ b/cmd/atlas/internal/cmdext/reader.go
@@ -206,9 +206,18 @@ func stateReaderHCL(_ context.Context, config *StateReaderConfig, paths []string
 			config.Dev.URL.Schema,
 		)
 	}
-	var normalized bool
+	var (
+		normalized  bool
+		schemaScope string
+	)
+	// The "Schema" below indicates the HCL represents a single
+	// database schema, and the work is scoped to this schema.
+	if len(realm.Schemas) == 1 && (config.Dev != nil && config.Dev.URL.Schema != "" || config.Client != nil && config.Client.URL.Schema != "") {
+		schemaScope = realm.Schemas[0].Name
+	}
 	return &StateReadCloser{
-		HCL: true,
+		HCL:    true,
+		Schema: schemaScope,
 		// Defer normalization until the first call to ReadState. This is required because the same
 		// dev-database is used for both migration replaying and schema normalization. As a result,
 		// objects created by the migrations, which are not yet supported by Atlas, such as functions,
diff --git a/cmd/atlas/internal/cmdlog/cmdlog.go b/cmd/atlas/internal/cmdlog/cmdlog.go
index 2f749438..a517cf12 100644
--- a/cmd/atlas/internal/cmdlog/cmdlog.go
+++ b/cmd/atlas/internal/cmdlog/cmdlog.go
@@ -319,6 +319,11 @@ Migrating to version {{ cyan .Target }}{{ with .Current }} from {{ cyan . }}{{ e
 	{{- else }}
 		{{- printf "  %s ok (%s)\n" (yellow "--") (yellow (.End.Sub .Start).String) }}
 	{{- end }}
+{{- else }}
+	{{- println }}
+	{{- with .Error }}
+		{{- println "   " (redBgWhiteFg .) }}
+	{{- end }}
 {{- end }}
 {{- println }}
 {{- println " " (cyan "-------------------------") }}
@@ -418,6 +423,7 @@ func (a *MigrateApply) Log(e migrate.LogEntry) {
 		f := a.Applied[len(a.Applied)-1]
 		f.Applied = append(f.Applied, e.SQL)
 	case migrate.LogError:
+		// Error during migration.
 		if l := len(a.Applied); l > 0 {
 			f := a.Applied[len(a.Applied)-1]
 			f.End = time.Now()
@@ -426,6 +432,11 @@ func (a *MigrateApply) Log(e migrate.LogEntry) {
 				Stmt: e.SQL,
 				Text: e.Error.Error(),
 			}
+			// Error during pre stages, such as
+			// scanning migration statements.
+		} else {
+			a.End = time.Now()
+			a.Error = e.Error.Error()
 		}
 	case migrate.LogDone:
 		n := time.Now()
diff --git a/doc/md/concepts/migration-directory-integrity.md b/doc/md/concepts/migration-directory-integrity.md
index cc80b1e6..af64f6d6 100644
--- a/doc/md/concepts/migration-directory-integrity.md
+++ b/doc/md/concepts/migration-directory-integrity.md
@@ -64,6 +64,6 @@ with the changes landed by Team B.
 Because of the merge conflict on the `atlas.sum` file, in order to land
 their changes, Team B would need to:
 1. Merge the latest changes from the master branch into their branch.
-2. If their migration file it not the latest one, they can use `atlas migrate rebase` to rebase their changes on top of all migrations.
+2. If their migration file is not the latest one, they can use `atlas migrate rebase` to rebase their changes on top of all migrations.
 3. In case there are any conflicts on the database schema (and application) level, resolve them and run [`atlas migrate hash`](/cli-reference#atlas-migrate-hash).
 4. Update the PR, wait for Atlas CI to pass, and merge the changes.
diff --git a/doc/md/guides/evaluation/01-intro.md b/doc/md/guides/evaluation/01-intro.md
new file mode 100644
index 00000000..ef508dfa
--- /dev/null
+++ b/doc/md/guides/evaluation/01-intro.md
@@ -0,0 +1,33 @@
+---
+id: intro
+title: Evaluating Atlas for your Use Case
+slug: /guides/evaluation/intro
+sidebar_label: Introduction
+---
+### Who is this guide for?
+
+This guide is for developers, architects, and DevOps engineers who are evaluating Atlas for their use case. 
+It will help you understand the core concepts of Atlas and how it can be used to manage your database schema.
+
+### What is Atlas?
+
+Atlas is a language-agnostic tool for managing and migrating database schemas using modern DevOps principles. 
+
+### What's in this guide?
+
+This guide is divided into the following sections:
+
+1. **Installation** - How to install Atlas and verify that it is able to understand your database.
+2. **Setting Up** - Setting up your project's structure for local work. 
+3. **Developer Workflow** - Review working with Atlas from the end-user perspective.
+4. **Setting Up CI Pipelines** - How to integrate Atlas into your CI/CD pipelines.
+5. **Security Checklist** - Things you should consider for when designing deployment pipelines.
+6. **Migrating  Existing Projects** - How to migrate existing projects to Atlas.
+
+### Need help? 
+
+If you are evaluating Atlas for commercial use, you might be eligible for free PoC support
+from the team developing Atlas including a dedicated, private Slack Connect channel 
+to unblock you in your research
+
+To apply for free PoC support [Click Here](#)
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/02-installation.mdx b/doc/md/guides/evaluation/02-installation.mdx
new file mode 100644
index 00000000..3f20f08d
--- /dev/null
+++ b/doc/md/guides/evaluation/02-installation.mdx
@@ -0,0 +1,36 @@
+---
+id: install
+title: Installing Atlas
+slug: /guides/evaluation/install
+sidebar_label: Installing Atlas
+---
+
+import Installation from '../../components/_installation_instructions.mdx';
+
+### Install Atlas Locally
+
+To get started with your Atlas evaluation, install the Atlas CLI on your local machine.
+
+<Installation />
+
+### Create an Atlas Account
+
+To get the most of your Atlas evaluation, create an Atlas account and use the CLI to log in.
+
+It is possible to use Atlas without logging in, but you will only be able to use a subset of its full
+feature set. For a more detailed comparison of the features available to logged-in and anonymous users,
+see the [Atlas Feature Comparison](/features) guide.
+
+:::info Data Privacy
+
+We do not collect your schemas or any data from your database unless you explicitly decide send it to us.
+To learn more about how the CLI handles your data head over to the [CLI Data Privacy](/cli/data-privacy)
+section.
+
+:::
+
+To log in to your account or create a new one, run the following command and follow the instructions:
+
+```bash
+atlas login
+```
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/03-connect.mdx b/doc/md/guides/evaluation/03-connect.mdx
new file mode 100644
index 00000000..07935e3a
--- /dev/null
+++ b/doc/md/guides/evaluation/03-connect.mdx
@@ -0,0 +1,173 @@
+---
+id: connect
+title: Connect to your database
+---
+
+:::info
+
+In this section we perform read-only operations and make no changes to your database.
+
+:::
+
+With the Atlas CLI installed and logged-in to your account, let's now make sure we can connect to your database
+with the CLI.
+
+## Step 1: Determine the database's URL
+
+Atlas uses a standard URL format to connect to databases and load schemas and migrations from various sources. The format
+below covers the supported parts of a URL, with subsequent sections providing more detailed examples.
+
+```
+driver://[username[:password]@]address/[schema|database][?param1=value1&...&paramN=valueN]
+```
+
+Here are some popular examples you can use:
+
+| Engine        |                                                                          |
+|---------------|--------------------------------------------------------------------------|
+| PostgreSQL    | `postgres://root:pass@localhost:5432/database?search_path=public`        |
+| MySQL         | `mysql://root:pass@localhost:3306/app_schema`                            |
+| SQL Server    | `sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master&mode=schema` |
+| ClickHouse    | `clickhouse://user:pass@localhost:9000/schema?secure=true`               |
+| More examples | In the [URL Docs](/concepts/url)                                                   |
+
+## Step 2: Choose connection scope
+
+### Schema vs Database-scope
+
+Most databases provide a way for users to namespace resources.  This feature is commonly named `schemas`.
+For instance, PostgreSQL and MySQL users may create additional schemas in a target database using a command such as:
+
+```sql
+CREATE SCHEMA auth;
+```
+
+Going forward, resources may be created under the `auth` schema, in a few ways:
+
+1. By qualifying the resource name with the schema name, so the database knows which specific
+  resource we are talking about, for example:
+  ```sql
+  create table `auth`.`session_log` (
+      -- ...
+  )
+  ```
+2. By using the `USE <schema>` statement before executing the relevant statement. For example:
+  ```
+  USE `auth`;
+  create table `session_log` (
+    -- ...
+  )
+  ```
+
+### Which kind of scope should you use?
+
+Depending on your use-case, you may require a schema or database scope connection. The following table summarizes
+some of these cases.
+
+| Use-case                                                 | Scope to use   |
+|----------------------------------------------------------|----------------|
+| All of my tables are in one schema                       | Schema-scope   |
+| I want to use qualified identifiers (e.g `auth`.`users`) | Database-scope |
+| I want to use database `EXTENSIONS` (Postgres) [Why?](/atlas-schema/hcl#extension)          | Database-scope |
+| I want to see the entire database                        | Database-scope |
+
+### Scoped connections
+
+By default, Atlas will create a database-scoped connection.  However, it is possible to limit the scope of
+the connection by providing it within the connection URL. For example:
+
+  | Engine        | Schema-scope                                          | Database-scope              |
+  |---------------|-------------------------------------------------------|-----------------------------|
+  | PostgreSQL    | `postgres://localhost:5432/database?search_path=public` | `postgres://:5432/database`   |
+  | MySQL         | `mysql://localhost:3306/app_schema`                     | `mysql://localhost:3306/`     |
+  | ClickHouse    | `clickhouse://localhost:9000/schema`                    | `clickhouse://localhost:9000` |
+  | SQL Server    | `sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master&mode=schema` | `sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master&mode=database` |
+  | More examples | In the [URL Docs](/concepts/url)                          |                             |
+
+## Test your connection
+
+Once you have determined your full connection URL including its scope, you can test that Atlas is able to
+connect to the database using the following command:
+
+```bash
+atlas schema inspect --url "<url>" --format "OK"
+```
+
+Be sure to replace `<url>` with your database's URL.
+
+If Atlas is able to connect to the given URL you should see the following output:
+
+```
+OK
+```
+
+### Troubleshooting
+
+#### My password contains non-alphanumeric characters
+
+Atlas uses standard [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) URLs, which means
+that "userinfo" section (which contains user and password) needs to be "pct-encoded" - commonly referred to
+as [URI encoding](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
+
+For example, `Pa$$w@rd` becomes `Pa%24%24w%40rd` and `a%b%c` becomes `a%25b%25c`.
+
+In case your password contains non-alphanumeric characters (as is often required by system administrators who want to
+increase minimal password complexity), you must encode your password before using it in your Atlas URL.
+
+Suppose your database password is `BnB+PjA`, attempting to use this password without encoding it first will result in
+an error message similar to:
+
+```
+Error: mysql: query system variables: dial tcp: lookup root:BnB+PjA:3309: no such host
+```
+
+To solve this, first encode your password using URL encoding. For example:
+
+```python
+import urllib.parse
+pw = "BnB+PjA"
+print(urllib.parse.quote(pw))
+```
+This program prints:
+```
+BnB%2BPjA
+```
+
+#### My connection times out
+
+When you try to connect to your database using Atlas, you might encounter an error message similar to:
+
+```
+Error: postgres: scanning system variables: dial tcp 10.0.5.243:5432: connect: operation timed out
+```
+
+Or
+
+```
+Error: mysql: query system variables: dial tcp 10.0.5.243:5432: connect: operation timed out
+```
+
+These errors suggest that Atlas is attempting to connect to the database but is unable to establish
+a network connection to the remote database at all.
+
+To resolve this error, ensure that you can establish a network connection to the database from your
+workstation. This might involve:
+
+* Connecting to your company's VPN which has access to the database
+* Connecting through a bastion server
+* Changing firewall rules for the database to allow a connection from your machine.
+
+:::info Other Issues
+
+If you encounter any issues during this step, don't hesitate to reach out to us.
+
+#### Commercial PoC
+
+Please reach out to us via our shared Slack Connect channel.
+
+#### Independent PoC
+
+Please use our [Community Support](/support) channels to contact our team. If possible,
+please supply us with a minimal example schema to reproduce the issue.
+
+:::
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/04-verify-atlas.mdx b/doc/md/guides/evaluation/04-verify-atlas.mdx
new file mode 100644
index 00000000..c2fd61a4
--- /dev/null
+++ b/doc/md/guides/evaluation/04-verify-atlas.mdx
@@ -0,0 +1,107 @@
+---
+id: verify-atlas
+title: Verify Atlas understands your Schema
+---
+
+After successfully connecting to your database using Atlas,  our next step will be to verify that Atlas
+is able to inspect your database schema and that it correctly normalizes it such that if re-applied to the
+database no diff will be detected.
+
+### Step 1: Export your database URL as an env var
+
+To make the examples in this section brief, start by setting a local environment variable
+containing the URL you determined for your database:
+
+```
+export DB_URL="<url>"
+```
+
+### Step 2: Store the schema in a local file
+
+Use the Atlas `schema inspect` command to connect to your database, calculate its schema graph
+and store it in a local file:
+
+```
+atlas schema inspect --url "$DB_URL" > schema.hcl
+```
+
+If everything worked correctly, you should find a file named `schema.hcl` in your current working
+directory which contains the [Atlas DDL](/atlas-schema/hcl) representation of your schema.
+
+### Step 3: Determine your Dev Database URL
+
+:::info
+
+Notice that when we discuss a **Dev Database** in the Atlas documentation we **DO NOT** refer to the
+local database you use for development, but to a different concept explained below.
+
+:::
+
+To operate correctly, Atlas utilizes a [Dev Database](/concepts/dev-database) to normalize and verify
+schemas. Essentially, a dev-database is an *empty* database of the same type and version that you use
+in production. When Atlas runs, it may run some operations against this database and is responsible
+for cleaning up after and leaving the database in an empty state.
+
+When working with Atlas, you can bring your own dev database, but most Atlas users prefer to use
+Atlas's built-in `docker://` driver which will spin up a local, ephemeral Docker container and dispose
+of it after for you.
+
+As we mentioned in the [previous section](03-connect.mdx#schema-vs-database-scope), Atlas operates
+differently if configured to use a database-scope vs a schema-scope. Be sure to use the same kind of
+scope for your dev-database to avoid miscalculations and other trouble. The following table summarizes
+some commonly used URLs.
+
+| Engine     | Scope          | URL Example                                 |
+|------------|----------------|---------------------------------------------|
+| MySQL      | Schema-scope   | `docker://mysql/8/dev`                        |
+|            | Database-scope | `docker://mysql/8`                            |
+| PostgreSQL | Schema-scope   | `docker://postgres/16/dev?search_path=public` |
+|            | Database-scope | `docker://postgres/16/dev`                    |
+| ClickHouse | Schema-scope   | `docker://clickhouse/23.11/dev`               |
+|            | Database-scope | `docker://clickhouse/23.11`                   |
+| SQL Server | Schema-scope   | `docker://sqlserver/2022-latest/dev?mode=schema` |
+|            | Database-scope | `docker://sqlserver/2022-latest/dev?mode=database` |
+| Others | | Find more examples in the [Dev Database](/concepts/dev-database) guide. |
+
+### Step 4: Verify Zero Diff
+
+Next, use Atlas's `schema diff` command to check that Atlas sees no difference between your inspected schema
+as it is represented in the `schema.hcl` file and the actual database schema:
+
+```shell
+atlas schema diff --dev-url <dev db url> --from file://schema.hcl --to "$DB_URL"
+```
+
+Be sure to replace `<dev db url>` with the Dev Database URL you determined in step 3.
+
+If everything works correctly, Atlas should print out a message similar to:
+
+```
+Schemas are synced, no changes to be made.
+```
+
+### Step 5 (Optional): Manual Verification
+
+If your database schema contains resources with esoteric or uncommon database features, you may want to manually review
+the inspected schema to make sure that it is inspected correctly.
+
+If you prefer to review this in plain SQL DDL commands instead of the Atlas's HCL syntax, run the following command:
+
+```shell
+atlas schema inspect --url "$DB_URL" --format "{{ sql . }}"
+```
+
+:::info Other Issues
+
+If you encounter any issues during this step, don't hesitate to reach out to us.
+
+#### Commercial PoC
+
+Please reach out to us via our shared Slack Connect channel.
+
+#### Independent PoC
+
+Please use our [Community Support](/support) channels to contact our team. If possible,
+please supply us with a minimal example schema to reproduce the issue.
+
+::: minimal example schema to reproduce the issue.
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/05-project-structure.mdx b/doc/md/guides/evaluation/05-project-structure.mdx
new file mode 100644
index 00000000..69c39e3f
--- /dev/null
+++ b/doc/md/guides/evaluation/05-project-structure.mdx
@@ -0,0 +1,69 @@
+---
+id: project-structure
+title: Project Structure
+---
+After successfully verifying Atlas can connect to your database and understand its schema, let's proceed
+to setting up your project.
+
+
+A typical project layout may look something similar to this:
+
+```text
+.
+├── atlas.hcl
+├── migrations
+│   ├── 20240520182315.sql
+│   ├── 20240520182336.sql
+│   └── atlas.sum
+└── schema.hcl
+```
+
+A typical Atlas project comprises 3 important parts:
+
+* Schema-as-Code - The desired state of your database should be present "as code" in the source control repository of
+  your project.
+* Project Configuration File - this file is typically named `atlas.hcl` and is located in the root directory
+  of your project. If you are using a "Monorepo" architecture, you will have one of these files per Atlas project.
+* Migrations - While Atlas supports both purely [Versioned and Declarative](/concepts/declarative-vs-versioned) workflows, currently most teams
+  that use Atlas in production use the mixed approach where the source of truth for the desired state of the schema
+  is stored "as code", but migrations are still explicitly managed in a dedicated directory, typically named `migrations/`.
+
+### Step 1: Create your project config file
+
+Before moving on to building CI and deployment pipelines, we will focus on building a setup for local development.
+
+Let's start this by creating our initial project configuration file.
+
+Create a file named `atlas.hcl` and place it at your project root.
+
+In this file define an `env` block for local development:
+
+```hcl
+env "local" {
+  dev = "docker://postgres/16/dev" // <-- Replace your with your dev database URL.
+}
+```
+
+Be sure to replace the `dev` URL with the URL you determined in [Step 3](verify-atlas#step-3-determine-your-dev-database-url)
+of the previous section.
+
+### Step 2: Verify your configuration works
+
+Let's repeat our verification from the previous section, this time using the `--env` flag instead of spelling out
+our Dev Database URL explicitly:
+
+```shell
+atlas schema diff --env local --from file://schema.hcl --to "$DB_URL"
+```
+
+This command will calculate the diff between the schema which we saved from your live database to `schema.hcl` in
+a previous step and the current schema of the database in `$DB_URL`.
+
+Unless your database schema changed in the interim, you should see the same output you got in the verification step
+of the previous section:
+
+```
+Schemas are synced, no changes to be made.
+```
+
+In the next section, we will explore how to define the desired schema of your database, as code.
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/06-schema-as-code.mdx b/doc/md/guides/evaluation/06-schema-as-code.mdx
new file mode 100644
index 00000000..956faa56
--- /dev/null
+++ b/doc/md/guides/evaluation/06-schema-as-code.mdx
@@ -0,0 +1,227 @@
+---
+id: schema-as-code
+title: Your Schema-as-Code
+---
+Atlas is built on the concept of "Database Schema-as-Code", where teams define the desired state of their database
+as part of their code, and use an automated tool (such as Atlas) to plan, verify and apply schema changes (migrations)
+automatically.
+
+Naturally, the first part of setting up your project is to determine how your "schema as code" project is going to be
+structured. Atlas provides a lot of flexibility around how to define this state as we will show below.
+
+## Step 1: Choose your language
+
+Atlas offers three main ways to define the desired state of your database schema:
+
+1. [Atlas DDL](/atlas-schema/hcl) - is an HCL-based syntax (similar to Terraform) for defining database schemas.
+For example:
+```hcl
+schema "default" {
+}
+
+table "users" {
+  schema = schema.default
+  column "name" {
+    type = varchar(100)
+  }
+  // ... more
+}
+   ```
+2. [Plain SQL](/atlas-schema/sql) - alternatively, you can use plain SQL DDL commands to define your database
+schema. For example:
+```sql
+CREATE TABLE `users` (
+    name varchar(100)
+);
+   ```
+3. [ORMs](/guides#orms) - Atlas can extract the desired database schema from ORM data models, for example:
+  ```python
+  from django.db import models
+
+  class User(models.Model):
+      name = models.CharField(max_length=100)
+  ```
+
+### What should you choose?
+
+As with any important engineering decision, there are pros and cons to every alternative, which you should weigh against
+your use case. Let's try to enumerate some benefits and potential issues with each alternative:
+
+|                | SQL                                                                                                                  | Atlas DDL                                                                                              | ORM                                                                                             |
+|----------------|----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
+| Familiarity    | Teams likely already know how to define SQL tables.                                                                  | New syntax specific to Atlas, familiar to teams using Terraform.                                       | Developers are used to defining data models in their favorite framework's API.                  |
+| Order          | Schema order matters; dependencies between resources  require careful attention.                                     | Resources can be defined in any order, providing flexibility.  Dependencies resolved by Atlas.         | Models can be defined in different files; dependencies are resolved by the ORM engine.          |
+| Editor Support | Imperative syntax limits IDE features like "Jump to Definition" and code completion.                                 | VSCode and JetBrains support with features like syntax highlighting and auto-completion.               | Editor support varies; some frameworks offer type-safe APIs while others use string annotations.|
+
+#### Familiarity
+- **SQL:** Your team probably already knows how to define SQL tables, making SQL a familiar choice for many teams,
+  leveraging existing knowledge and skills.
+- **Atlas DDL:** The syntax is new and specific to Atlas but will feel familiar to teams used to working with Terraform,
+  balancing the introduction of new concepts with leveraging Terraform's HCL familiarity.
+- **ORM:** Your developers are already used to defining data models in their favorite framework's API, which can speed
+  up development and reduce the learning curve for new team members.
+
+#### Order
+
+- **SQL:** Schemas must be replayable on a target database, meaning the order in which statements are written matters.
+  For example, you cannot define a table that references another table via a foreign key before the dependent table is defined. This requires either disabling foreign key checks or splitting the table definition into a `CREATE` statement followed by an `ALTER` statement, complicating schema management and requiring careful planning.
+- **Atlas DDL:** Atlas DDL is based on HCL, the same configuration language used by Terraform. Resources can be defined
+  in any order, helping with logically splitting resources into different domains and offering more flexibility.
+  This reduces mental overhead and simplifies operations for end developers.
+- **ORM:** This depends on the ORM specifics, but in general, ORM Models can be defined in different files where their
+  dependencies are resolved by the ORM engine. This modularity simplifies development and maintenance of data models.
+
+#### Editor Support
+- **SQL:** Because SQL DDL is an imperative syntax, important IDE features (such as "Jump to Definition" and
+  code completion) do not work great. This can hinder development efficiency and increase the potential for errors.
+- **Atlas DDL:** Editor support for both VSCode and JetBrains includes syntax highlighting, auto-completion, syntax
+  checking, jump to definition, multi-file support, and more. This comprehensive support enhances developer productivity and reduces the likelihood of errors.
+- **ORM:** Editor support greatly varies. Some frameworks provide a 100% type-safe API which the editor understands,
+  while others heavily rely on string-based annotations. Depending on the framework, developer efficiency and code
+  robustness may vary.
+
+
+### Must you choose only one?
+
+In some cases, no alternative checks all the boxes and you need to find a way to build schemas that are
+built from multiple building blocks. For example, you may want to use your favorite ORM to describe your schema
+only to discover that it lacks support for some needed database functionality (e.g `VIEW` or `TRIGGER` resources).
+
+In cases like these, we advise using the `composite_schema` data source which can be used to layer multiple schema
+definitions one on top of the other. This way you can have your base models defined as _Django Models_, but additional
+views and triggers layered on top in Atlas DDL.
+
+Here's a basic example of how a `composite_schema` might look like:
+
+```
+data "composite_schema" "project" {
+  schema "inventory" {
+    url = data.external_schema.django.url
+  }
+  schema "triggers" {
+    url = "file://path/to/triggers.hcl"
+  }
+}
+```
+
+To learn more about `composite_schema`, head over to the [documentation](/atlas-schema/projects#data-source-composite_schema)
+
+## Step 2: Add your schema files
+
+After you have determined what you would like to use as the desired state for your Database Schema-as-Code
+setup with Atlas, let's add the relevant files to our project.
+
+### Option A: Atlas DDL
+
+Use the following command to inspect your target database schema to create an initial baseline for your project
+with Atlas DDL:
+
+```shell
+atlas schema inspect --url "$DB_URL" --env local  > schema.hcl
+```
+
+This command tells Atlas to connect to the database at `$DB_URL`, inspect it, use the
+Dev Database defined in the `local` env.  By default, Atlas DDL is used as the output format.
+We then redirect the output from Atlas into a new file, `schema.hcl` which we will use the the
+source schema for our project.
+
+Next, update your project configuration file, `atlas.hcl`, to add the `src` attribute which tells
+Atlas it can find the desired state of the database in the given path:
+
+```hcl
+env "local" {
+  //highlight-next-line
+  src = "file://schema.hcl"
+  dev = "docker://postgres/16/dev" // <-- Replace your with your dev database URL.
+}
+```
+
+### Option B: Plain SQL
+
+Use the following command to inspect your target database schema to create an initial baseline for your project
+with plain SQL:
+
+```shell
+atlas schema inspect --url "$DB_URL" --env local --format "{{ sql . \" \"}}" > schema.sql
+```
+
+This command tells Atlas to connect to the database at `$DB_URL`, inspect it, use the
+Dev Database defined in the `local` env and format it as plain SQL.  We then redirect the output
+from Atlas into a new file, `schema.sql` which we will use the the source schema for our project.
+
+Next, update your project configuration file, `atlas.hcl`, to add the `src` attribute which tells
+Atlas it can find the desired state of the database in the given path:
+
+```hcl
+env "local" {
+  //highlight-next-line
+  src = "file://schema.sql"
+  dev = "docker://postgres/16/dev" // <-- Replace your with your dev database URL.
+}
+```
+
+### Option C: ORMs
+
+ORMs require a bit more involvement in setting up our project, so refer to the relevant ORM guide:
+
+#### Go
+
+* [GORM](/guides/orms/gorm)
+* [Ent](#)
+* [Beego](/guides/orms/beego)
+
+#### Python
+
+* [SQLAlchemy](/guides/orms/sqlalchemy)
+* [Django](/guides/orms/django)
+
+#### Java
+
+* [Hibernate](/guides/orms/hibernate)
+
+#### Node.js
+
+* [TypeORM](/guides/orms/typeorm)
+* [Sequelize](/guides/orms/sequelize)
+
+All of the examples above are a result of our team's work with our users and customers.
+If you are missing something on this list, please don't hesitate to reach out to someone
+from our team!
+
+## Step 3: Verify our setup
+
+Next, let's verify Atlas is able to read our desired schema, by introducing a new flag for
+the `schema inspect` command, `--web`. After running a normal inspection of our database schema,
+when provided with this flag, Atlas will offer to visualize our database schema in an online
+ER Diagram on Atlas Cloud:
+
+```shell
+atlas schema inspect --env local --url "env://src" --web
+```
+
+Notice that this command uses `env://src` as the target URL for inspection, meaning "the schema represented by the
+`src` attribute of the `local` environment block.
+
+When you use the `--web` flag you can choose if you want to upload it a public link or privately
+to your Atlas Cloud account:
+
+```
+? Where would you like to share your schema visualization?:
+  ▸ Publicly (gh.atlasgo.cloud)
+    Privately (your-account.atlasgo.cloud)
+```
+
+Public links can be shared with your colleagues without requiring them to have an Atlas Cloud account
+while private links can only be accessed from within your account.
+
+After choosing the option you prefer, if everything worked correctly you should see a diagram similar to
+this:
+
+![](https://atlasgo.io/uploads/erd-example.png)
+
+:::info Alternative: Text-based Inspection
+
+If you do not wish to visualize your schema on Atlas Cloud at this point, you can omit the `--web` option
+to get a textual representation of your schema.
+
+:::
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/07-setup-migrations.mdx b/doc/md/guides/evaluation/07-setup-migrations.mdx
new file mode 100644
index 00000000..9b8ddf57
--- /dev/null
+++ b/doc/md/guides/evaluation/07-setup-migrations.mdx
@@ -0,0 +1,96 @@
+---
+id: setup-migrations
+title: Setup Versioned Migrations
+---
+
+## Intro
+
+Similarly to other migration tools, in its _Versioned Migrations flow_ Atlas keeps track of schema changes in a
+_Migration Directory_.  This is a directory containing SQL migration scripts, which are named following this convention
+
+```
+<version>_<label>.sql
+```
+For example:
+
+```
+20240520182336_add_users_table.sql
+```
+The label is optional, so this filename is also valid:
+```
+20240520182336.sql
+```
+By default, Atlas generates migration files with the `YYYYMMDDHHMMSS.sql` naming convention, where `YYYY` is the year,
+`MM` is the month, `DD` is the day, `HH` is the hour, `MM` is the minute, and `SS` is the second when the file was created.
+However, you may choose to name your files in another way, as long as versions are numeric and ordered lexicographically.
+
+In this section, we generate the baseline migration directory for your project from your "schema-as-code".
+
+## Step 1: Configuration
+
+Let's further evolve our `atlas.hcl` configuration file to describe how versioned migrations should be handled.
+
+By default, migrations will be stored in the `migrations` directory relative to the current working directory, however
+it is good practice to explicitly define the location for your migration directory in the project configuration file.
+Add the following line to your `local` env block:
+
+```hcl {3-10}
+env "local" {
+  // .. redacted for brevity
+  migration {
+    dir = "file://migrations"
+  }
+  format {
+    migrate {
+      diff = "{{ sql . \"  \" }}"
+    }
+  }
+}
+```
+
+The `format` block configures migrations to be created with indentation for improved readability.
+
+## Step 2: Create the Baseline Migration
+
+The next step is to create a baseline migration which contains our project schema up until this point.
+
+To plan this initial migration run the following command:
+
+```shell
+atlas migrate diff --env local baseline
+```
+
+Observe two new files are created under the `migrations/` directory:
+
+```
+.
+├── 20240604131146_baseline.sql
+└── atlas.sum
+```
+
+The first file is the baseline migration, and the second, `atlas.sum`, is the migration directory
+[integrity file](/concepts//migration-directory-integrity) which protects your project from conflicts
+between developers working in parallel.
+
+### How does this work?
+
+Here's what Atlas does when you run `atlas migrate diff`:
+
+1. It reads the desired schema as defined in the environment `src` attribute.
+2. It replays all migrations on the Dev Database and takes a snapshot of the schema.
+3. Atlas calculates a diff between the desired state (step 1) and the current state (step 2)
+4. Atlas writes a new migration file to the `migrations/` directory and updates the `atlas.sum` file.
+
+## Step 3: Verify the generated migration
+
+To verify the migration was calculated correctly you can compare it to your live database:
+
+```
+atlas schema diff --env local --from "$DB_URL" --to file://migrations
+```
+
+If all went well, you should see a message similar to:
+
+```
+Schemas are synced, no changes to be made.
+```
\ No newline at end of file
diff --git a/doc/md/guides/evaluation/08-versioned-migrations-flows.mdx b/doc/md/guides/evaluation/08-versioned-migrations-flows.mdx
new file mode 100644
index 00000000..b783d6c2
--- /dev/null
+++ b/doc/md/guides/evaluation/08-versioned-migrations-flows.mdx
@@ -0,0 +1,4 @@
+---
+id: dev-flow-versioned
+title: Dev Flows for Versioned Migrations
+---
\ No newline at end of file
diff --git a/doc/md/integrations/circleci-orbs.mdx b/doc/md/integrations/circleci-orbs.mdx
new file mode 100644
index 00000000..f0b63dc6
--- /dev/null
+++ b/doc/md/integrations/circleci-orbs.mdx
@@ -0,0 +1,1030 @@
+---
+title: CircleCI Orbs
+id: circleci-orbs
+slug: /integrations/circleci-orbs
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+[CircleCI Orbs](https://circleci.com/orbs) are reusable packages of CircleCI configuration that can be shared across projects. 
+They provide a way to simplify your CircleCI configuration by encapsulating common tasks into a single line of code.
+
+Atlas provides a number of Orbs to help you integrate Atlas into your CircleCI workflows.
+
+| Action                                                | Use Case                                            |
+|-------------------------------------------------------|-----------------------------------------------------|
+| [atlas-orb/setup](https://github.com/ariga/atlas-orb/blob/master/src/commands/setup.yaml) | Install Atlas and authenticate with Atlas Cloud      |
+| [atlas-orb/migrate_push](https://github.com/ariga/atlas-orb/blob/master/src/commands/migrate_push.yml)   | Push your migration directory to Atlas Cloud (atlasgo.cloud) |
+| [atlas-orb/migrate_lint](https://github.com/ariga/atlas-orb/blob/master/src/commands/migrate_lint.yml)        | Lint migration changes with Atlas (Required `atlas login`)  |
+| [atlas-orb/migrate_apply](https://github.com/ariga/atlas-orb/blob/master/src/commands/migrate_apply.yml)   | Apply migrations to a database |
+| [atlas-orb/migrate_down](https://github.com/ariga/atlas-orb/blob/master/src/commands/migrate_down.yml)   | Revert migrations to a database. |
+
+## `atlas-orb/setup`
+
+The [atlas-orb/setup](https://github.com/ariga/atlas-orb/blob/master/src/commands/setup.yaml) action can be used to install the Atlas CLI and authenticate with Atlas Cloud.
+
+### Usage
+
+```yaml title=".circleci/config.yml"
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - atlas-orb/setup:
+          version: "latest"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+### Inputs
+
+* `cloud_token_env` - (Optional) The Atlas Cloud token to use for authentication. To create
+  a cloud token see the [docs](https://atlasgo.io/cloud/bots). Defaults to `ATLAS_TOKEN` environment variable.
+* `version` - (Optional) The version of the Atlas CLI to install.  Defaults to the latest
+  version.
+
+## `atlas-orb/migrate_push`
+
+Push the current version of your migration directory to Atlas Cloud.
+
+### Usage
+
+<Tabs
+defaultValue="mysql"
+values={[
+    {label: 'MySQL', value: 'mysql'},
+    {label: 'MariaDB', value: 'maria'},
+    {label: 'PostgreSQL', value: 'postgres'},
+    {label: 'SQLite', value: 'sqlite'},
+    {label: 'SQL Server', value: 'sqlserver'},
+    {label: 'Clickhouse', value: 'clickhouse'},
+]}>
+<TabItem value="mysql">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mysql:8
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MySQL
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "mysql://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="maria">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mariadb:10.6
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MariaDB
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "maria://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="postgres">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/postgres:15.0
+        environment:
+          POSTGRES_DB: dev
+          POSTGRES_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Postgres
+          command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "postgres://postgres:pass@localhost:5432/dev?sslmode=disable"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="sqlite">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+    environment:
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "sqlite://file?mode=memory&_fk=1"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+</TabItem>
+<TabItem value="sqlserver">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: mcr.microsoft.com/mssql/server:2022-latest
+        environment:
+          ACCEPT_EULA: Y
+          MSSQL_PID: Developer
+          MSSQL_SA_PASSWORD: P@ssw0rd0995
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for SQL Server
+          command: dockerize -wait tcp://127.0.0.1:1433 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="clickhouse">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: clickhouse/clickhouse-server:23.10
+        environment:
+          CLICKHOUSE_DB: test
+          CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
+          CLICKHOUSE_PASSWORD: pass
+          CLICKHOUSE_USER: root
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Clickhouse
+          command: dockerize -wait tcp://127.0.0.1:9000 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_push:
+          dir_name: my-project
+          dev_url: "clickhouse://root:pass@localhost:9000/test"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+</Tabs>
+
+### Inputs
+
+All inputs are optional as they may be specified in the Atlas configuration file.
+
+* `dir` - The URL of the migration directory to push.  For example: `file://migrations`.
+Read more about [Atlas URLs](https://atlasgo.io/concepts/url).
+* `dir_name` - The name (slug) of the project in Atlas Cloud.
+* `dev_url` - The URL of the dev-database to use for analysis.  For example: `mysql://root:pass@localhost:3306/dev`.
+Read more about [dev-databases](https://atlasgo.io/concepts/dev-database).
+* `tag` - The tag to apply to the pushed migration directory.  By default the current git commit hash is used.
+* `config` - The path to the Atlas configuration file. By default, Atlas will look for a file.
+named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.
+Learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).
+* `env` - The environment to use from the Atlas configuration file.  For example, `dev`.
+* `vars` - Extra variables to pass to the Atlas configuration file. For example, `key=value key2=values`.
+* `working_directory` - The working directory to run from. Defaults to project root.
+
+## `atlas-orb/migrate_lint` (Required `atlas login`)
+
+Teams using CircleCI that wish to ensure all changes to their database schema are safe
+can use the [`atlas-orb/migrate_lint`](https://github.com/ariga/atlas-orb/blob/master/src/commands/migrate_lint.yml) CircleCI Orb.
+
+This action is used for [linting migration directories](/versioned/lint)
+using the `atlas migrate lint` command. This command  validates and analyzes the contents
+of migration directories and generates insights and diagnostics on the selected changes:
+
+* Ensure the migration history can be replayed from any point at time.
+* Protect from unexpected history changes when concurrent migrations are written to the migration directory by
+  multiple team members. Read more about the consistency checks in the section below.
+* Detect whether destructive or irreversible changes have been made or whether they are dependent on tables'  
+  contents and can cause a migration failure.
+
+### Usage
+
+Add `.circleci/config.yml` to your repo with the following contents:
+
+<Tabs
+defaultValue="mysql"
+values={[
+    {label: 'MySQL', value: 'mysql'},
+    {label: 'MariaDB', value: 'maria'},
+    {label: 'PostgreSQL', value: 'postgres'},
+    {label: 'SQLite', value: 'sqlite'},
+    {label: 'SQL Server', value: 'sqlserver'},
+    {label: 'Clickhouse', value: 'clickhouse'},
+]}>
+<TabItem value="mysql">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mysql:8
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MySQL
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "mysql://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="maria">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mariadb:10.6
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MariaDB
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "maria://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="postgres">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/postgres:15.0
+        environment:
+          POSTGRES_DB: dev
+          POSTGRES_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Postgres
+          command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "postgres://postgres:pass@localhost:5432/dev?sslmode=disable"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="sqlite">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "sqlite://file?mode=memory&_fk=1"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+</TabItem>
+<TabItem value="sqlserver">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: mcr.microsoft.com/mssql/server:2022-latest
+        environment:
+          ACCEPT_EULA: Y
+          MSSQL_PID: Developer
+          MSSQL_SA_PASSWORD: P@ssw0rd0995
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - run:
+          name: Wait for SQL Server
+          command: dockerize -wait tcp://127.0.0.1:1433 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="clickhouse">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: clickhouse/clickhouse-server:23.10
+        environment:
+          CLICKHOUSE_DB: test
+          CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
+          CLICKHOUSE_PASSWORD: pass
+          CLICKHOUSE_USER: root
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+      GITHUB_TOKEN: "your-github-token"
+      GITHUB_REPOSITORY: "your-repo-name" # for example, "ariga/atlas-orb"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Clickhouse
+          command: dockerize -wait tcp://127.0.0.1:9000 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_lint:
+          dir_name: my-project
+          dev_url: "clickhouse://root:pass@localhost:9000/test"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+</Tabs>
+
+### Inputs
+
+All inputs are optional as they may be specified in the Atlas configuration file.
+
+* `dir` - The URL of the migration directory to lint.  For example: `file://migrations`.
+  Read more about [Atlas URLs](https://atlasgo.io/concepts/url).
+* `dir_name` - The name (slug) of the project in Atlas Cloud.
+* `dev_url` - The URL of the dev-database to use for analysis.  For example: `mysql://root:pass@localhost:3306/dev`.
+  Read more about [dev-databases](https://atlasgo.io/concepts/dev-database).
+* `config` - The path to the Atlas configuration file.  By default, Atlas will look for a file
+  named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.
+  Learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).
+* `env` - The environment to use from the Atlas configuration file.  For example, `dev`.
+* `vars` - Extra variables to pass to the Atlas configuration file. For example, `key=value key2=values`.
+* `working_directory` - The working directory to run from. Defaults to project root.
+* `github_token_env` - Specify the environment variable name that contains the GitHub token.
+  Defaults to `GITHUB_TOKEN` environment variable.
+* `github_repository_env` - Specify the environment variable name that contains the GitHub repository name in the format `owner/repo`.
+  Defaults to `GITHUB_REPOSITORY` environment variable.
+
+:::note
+The `GITHUB_TOKEN` and `GITHUB_REPOSITORY` environment variables are required for the `atlas-orb/migrate_lint` action to work.
+These variables are used to post lint results to the GitHub Pull Request as comments.
+If you want to use a different environment variable name, you can specify it using the `github_token_env` and `github_repository_env` inputs
+:::
+
+## `atlas-orb/migrate_apply`
+
+Push the current version of your migration directory to Atlas Cloud.
+
+### Usage
+
+<Tabs
+defaultValue="mysql"
+values={[
+    {label: 'MySQL', value: 'mysql'},
+    {label: 'MariaDB', value: 'maria'},
+    {label: 'PostgreSQL', value: 'postgres'},
+    {label: 'SQLite', value: 'sqlite'},
+    {label: 'SQL Server', value: 'sqlserver'},
+    {label: 'Clickhouse', value: 'clickhouse'},
+]}>
+<TabItem value="mysql">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mysql:8
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MySQL
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: my-project
+          url: "mysql://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="maria">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mariadb:10.6
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MariaDB
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: atlas://my-project
+          url: "maria://root:pass@localhost:3306/dev"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="postgres">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/postgres:15.0
+        environment:
+          POSTGRES_DB: dev
+          POSTGRES_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Postgres
+          command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: atlas://my-project
+          url: "postgres://postgres:pass@localhost:5432/dev?sslmode=disable"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="sqlite">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+    environment:
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: atlas://my-project
+          url: "sqlite://file?mode=memory&_fk=1"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+</TabItem>
+<TabItem value="sqlserver">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: mcr.microsoft.com/mssql/server:2022-latest
+        environment:
+          ACCEPT_EULA: Y
+          MSSQL_PID: Developer
+          MSSQL_SA_PASSWORD: P@ssw0rd0995
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for SQL Server
+          command: dockerize -wait tcp://127.0.0.1:1433 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: atlas://my-project
+          url: "sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="clickhouse">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: clickhouse/clickhouse-server:23.10
+        environment:
+          CLICKHOUSE_DB: test
+          CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
+          CLICKHOUSE_PASSWORD: pass
+          CLICKHOUSE_USER: root
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Clickhouse
+          command: dockerize -wait tcp://127.0.0.1:9000 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_apply:
+          dir: atlas://my-project
+          url: "clickhouse://root:pass@localhost:9000/test"
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+</Tabs>
+
+### Inputs
+
+All inputs are optional as they may be specified in the Atlas configuration file.
+
+* `url` - The URL of the target database. For example: `mysql://root:pass@localhost:3306/dev`.
+* `dir` - The URL of the migration directory to apply. For example: `atlas://dir-name` for cloud based directories or `file://migrations` for local ones.
+* `config` - The path to the Atlas configuration file. By default, Atlas will look for a file
+named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.
+Learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).
+* `env` - The environment to use from the Atlas configuration file.  For example, `dev`.
+* `dry_run` - Print SQL without executing it. Defaults to `false`.
+* `vars` - Extra variables to pass to the Atlas configuration file. For example, `key=value key2=values`.
+* `working_directory` - The working directory to run from. Defaults to project root.
+
+## `atlas-orb/migrate_down`
+
+Revert migrations to a database.
+
+### Usage
+
+<Tabs
+defaultValue="mysql"
+values={[
+    {label: 'MySQL', value: 'mysql'},
+    {label: 'MariaDB', value: 'maria'},
+    {label: 'PostgreSQL', value: 'postgres'},
+    {label: 'SQLite', value: 'sqlite'},
+    {label: 'SQL Server', value: 'sqlserver'},
+    {label: 'Clickhouse', value: 'clickhouse'},
+]}>
+<TabItem value="mysql">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mysql:8
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MySQL
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: my-project
+          url: "mysql://root:pass@localhost:3306/example"
+          dev_url: "mysql://root:pass@localhost:3306/dev"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="maria">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/mariadb:10.6
+        environment:
+          MYSQL_DATABASE: dev
+          MYSQL_ROOT_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for MariaDB
+          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: atlas://my-project
+          url: "maria://root:pass@localhost:3306/example"
+          dev_url: "maria://root:pass@localhost:3306/dev"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="postgres">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: cimg/postgres:15.0
+        environment:
+          POSTGRES_DB: dev
+          POSTGRES_PASSWORD: pass
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Postgres
+          command: dockerize -wait tcp://127.0.0.1:5432 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: atlas://my-project
+          url: "postgres://postgres:pass@localhost:5432/example?sslmode=disable"
+          dev_url: "postgres://postgres:pass@localhost:5432/dev"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="sqlite">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+    environment:
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: atlas://my-project
+          url: "sqlite://file?mode=memory&_fk=1"
+          dev_url: "sqlite://file2?mode=memory&_fk=1"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+</TabItem>
+<TabItem value="sqlserver">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: mcr.microsoft.com/mssql/server:2022-latest
+        environment:
+          ACCEPT_EULA: Y
+          MSSQL_PID: Developer
+          MSSQL_SA_PASSWORD: P@ssw0rd0995
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for SQL Server
+          command: dockerize -wait tcp://127.0.0.1:1433 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: atlas://my-project
+          url: "sqlserver://sa:P@ssw0rd0995@localhost:1433?database=master"
+          dev_url: "sqlserver://sa:P@ssw0rd0995@localhost:1433?database=dev"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+<TabItem value="clickhouse">
+
+```yaml
+version: 2.1
+orbs:
+  atlas-orb: ariga/atlas-orb@0.0.6
+jobs:
+  push-dir:
+    docker:
+      - image: cimg/base:current
+      - image: clickhouse/clickhouse-server:23.10
+        environment:
+          CLICKHOUSE_DB: test
+          CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
+          CLICKHOUSE_PASSWORD: pass
+          CLICKHOUSE_USER: root
+    environment:
+      # Define those envs in CircleCI context to keep them secure
+      ATLAS_TOKEN: "your-atlas-token"
+    steps:
+      - checkout
+      - run:
+          name: Wait for Clickhouse
+          command: dockerize -wait tcp://127.0.0.1:9000 -timeout 60s
+      - atlas-orb/setup:
+          version: "latest"
+      - atlas-orb/migrate_down:
+          dir: atlas://my-project
+          url: "clickhouse://root:pass@localhost:9000/test"
+          dev_url: "clickhouse://root:pass@localhost:9000/dev"
+          amount: 1
+workflows:
+  use-atlas:
+    jobs:
+      - push-dir
+```
+
+</TabItem>
+</Tabs>
+
+### Inputs
+
+All inputs are optional as they may be specified in the Atlas configuration file.
+
+* `url` - The URL of the target database. For example: `mysql://root:pass@localhost:3306/dev`.
+* `dir` - The URL of the migration directory to apply. For example: `atlas://dir-name` for cloud based directories or `file://migrations` for local ones.
+* `config` - The path to the Atlas configuration file. By default, Atlas will look for a file
+named `atlas.hcl` in the current directory. For example, `file://config/atlas.hcl`.
+Learn more about [Atlas configuration files](https://atlasgo.io/atlas-schema/projects).
+* `env` - The environment to use from the Atlas configuration file.  For example, `dev`.
+* `amount` - The number of migrations to revert. Defaults to 1.
+* `to_version` - To which version to revert.
+* `to_tag` - To which tag to revert.
+* `wait_timeout` -  Time after which no other retry attempt is made and the action exits. If not set, only one attempt is made.
+* `wait-interval` - Time in seconds between different migrate down attempts, useful when waiting for plan approval, defaults to 1s.
+* `vars` - Extra variables to pass to the Atlas configuration file. For example, `key=value key2=values`.
+* `working_directory` - The working directory to run from. Defaults to project root.
\ No newline at end of file
diff --git a/doc/website/sidebars.js b/doc/website/sidebars.js
index ee8255b5..43a26c9d 100644
--- a/doc/website/sidebars.js
+++ b/doc/website/sidebars.js
@@ -127,6 +127,7 @@ module.exports = {
                     id: 'integrations/kubernetes/operator'
                 },
                 {type: 'doc', id: 'integrations/github-actions', label: 'GitHub Actions'},
+                {type: 'doc', id: 'integrations/circleci-orbs', label: 'CircleCI Orbs'},
                 {type: 'doc', id: 'integrations/terraform-provider', label: 'Terraform Provider'},
                 {type: 'doc', id: 'integrations/go-sdk', label: 'Go SDK'},
             ]
@@ -140,8 +141,8 @@ module.exports = {
             label: 'CLI Reference',
             collapsed: false,
             link: {
-              type: 'doc',
-              id: 'cli-reference'
+                type: 'doc',
+                id: 'cli-reference'
             },
             items: [
                 {
@@ -170,9 +171,9 @@ module.exports = {
             id: 'guides/guides'
         },
         {
-          type: 'category',
-          label: 'For Platform Teams',
-          collapsed: false,
+            type: 'category',
+            label: 'For Platform Teams',
+            collapsed: false,
             items: [
                 {
                     type: 'doc',
@@ -527,5 +528,58 @@ module.exports = {
                 },
             ]
         }
+    ],
+    eval: [
+        {
+            type: 'category',
+            label: 'Evaluating Atlas',
+            collapsed: false,
+            items: [
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/intro'
+                },
+            ]
+        },
+        {
+            type: 'category',
+            label: 'Installation',
+            collapsed: false,
+            items: [
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/install'
+                },
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/connect'
+                },
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/verify-atlas',
+                    label: 'Verify Atlas'
+                }
+            ]
+        },
+        {
+            type: 'category',
+            label: 'Setting Up',
+            collapsed: false,
+            items: [
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/project-structure'
+                },
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/schema-as-code'
+                },
+                {
+                    type: 'doc',
+                    id: 'guides/evaluation/setup-migrations',
+                    label: 'Migration Directory'
+                }
+            ]
+        },
     ]
 };
diff --git a/go.mod b/go.mod
index 6f1b6de9..ce768df0 100644
--- a/go.mod
+++ b/go.mod
@@ -7,13 +7,14 @@ require (
 	github.com/go-openapi/inflect v0.19.0
 	github.com/hashicorp/hcl/v2 v2.13.0
 	github.com/stretchr/testify v1.8.2
-	github.com/zclconf/go-cty v1.8.0
+	github.com/zclconf/go-cty v1.14.4
 	golang.org/x/mod v0.15.0
 )
 
 require (
 	github.com/agext/levenshtein v1.2.1 // indirect
 	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
 	github.com/kr/text v0.2.0 // indirect
diff --git a/go.sum b/go.sum
index 448c7693..d0360059 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,8 @@ github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tj
 github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
 github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -12,17 +14,12 @@ github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNP
 github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
 github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
 github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
 github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
@@ -40,26 +37,14 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
-github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
-github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
-github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
+github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
 golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/ci/ci_go.tmpl b/internal/ci/ci_go.tmpl
index c1968258..cdc50ffa 100644
--- a/internal/ci/ci_go.tmpl
+++ b/internal/ci/ci_go.tmpl
@@ -96,7 +96,7 @@ jobs:
         run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...
         working-directory: sql
       - name: Run schemahcl tests
-        run: go test -race ./...
+        run: go test {{ with $.Tags }}-tags={{ . }} {{ end }}-race ./...
         working-directory: schemahcl
 
   cli:
diff --git a/internal/integration/go.mod b/internal/integration/go.mod
index 121d05a4..aef6b5d9 100644
--- a/internal/integration/go.mod
+++ b/internal/integration/go.mod
@@ -16,7 +16,7 @@ require (
 	github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e
 	github.com/rogpeppe/go-internal v1.9.0
 	github.com/stretchr/testify v1.8.4
-	github.com/zclconf/go-cty v1.10.0
+	github.com/zclconf/go-cty v1.14.4
 )
 
 require (
@@ -31,6 +31,7 @@ require (
 	github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
 	github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
 	github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
+	github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
 	github.com/aws/aws-sdk-go v1.49.0 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.24.0 // indirect
 	github.com/aws/aws-sdk-go-v2/config v1.26.1 // indirect
diff --git a/internal/integration/go.sum b/internal/integration/go.sum
index e3c668f7..f49c116a 100644
--- a/internal/integration/go.sum
+++ b/internal/integration/go.sum
@@ -31,6 +31,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8
 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
 github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
+github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
+github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
 github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY=
 github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
 github.com/aws/aws-sdk-go-v2 v1.20.1/go.mod h1:NU06lETsFm8fUC6ZjhgDpVBcGZTFQ6XM+LZWZxMI4ac=
@@ -124,10 +126,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -257,11 +257,9 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4=
 github.com/vektah/gqlparser/v2 v2.5.1/go.mod h1:mPgqFBu/woKTVYWyNk8cO3kh4S/f4aRFZrvOnp3hmCs=
-github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
-github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0=
-github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
+github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
+github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
 go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
@@ -293,9 +291,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -332,7 +328,6 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
@@ -356,7 +351,6 @@ google.golang.org/api v0.151.0 h1:FhfXLO/NFdJIzQtCqjpysWwqKk8AzGWBUhMIx67cVDU=
 google.golang.org/api v0.151.0/go.mod h1:ccy+MJ6nrYFgE3WgRx/AMXOxOmU8Q4hSa+jjibzhxcg=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
 google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -390,7 +384,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
 google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/schemahcl/schemahcl.go b/schemahcl/schemahcl.go
index 0170b2d3..abc101db 100644
--- a/schemahcl/schemahcl.go
+++ b/schemahcl/schemahcl.go
@@ -34,7 +34,8 @@ type (
 		typedblk         map[string]map[string]BlockFunc
 		// Optional context to pass to dynamic block handlers,
 		// such as data-sources, type-blocks, etc.
-		ctx context.Context
+		ctx     context.Context
+		withPos bool
 	}
 	// Option configures a Config.
 	Option func(*Config)
@@ -98,6 +99,13 @@ func WithScopedEnums[T interface{ ~string }](path string, enums ...T) Option {
 	}
 }
 
+// WithPos attaches parse positions to returned Resources and Attrs.
+func WithPos() Option {
+	return func(c *Config) {
+		c.withPos = true
+	}
+}
+
 // WithVariables registers a list of variables to be injected into the context.
 func WithVariables(vars map[string]cty.Value) Option {
 	return func(c *Config) {
@@ -583,6 +591,9 @@ func (s *State) toAttrs(ctx *hcl.EvalContext, vr SchemaValidator, hclAttrs hclsy
 			return nil, err
 		}
 		at := &Attr{K: hclAttr.Name}
+		if s.config.withPos {
+			at.SetRange(&hclAttr.SrcRange)
+		}
 		switch t := value.Type(); {
 		case isRef(value):
 			if !value.Type().HasAttribute("__ref") {
@@ -694,6 +705,9 @@ func (s *State) toResource(ctx *hcl.EvalContext, vr SchemaValidator, block *hcls
 		return nil, err
 	}
 	spec = &Resource{Type: block.Type}
+	if s.config.withPos {
+		spec.SetRange(&block.TypeRange)
+	}
 	switch len(block.Labels) {
 	case 0:
 	case 1:
diff --git a/schemahcl/spec.go b/schemahcl/spec.go
index a2b0b88b..505eda05 100644
--- a/schemahcl/spec.go
+++ b/schemahcl/spec.go
@@ -11,6 +11,8 @@ import (
 	"strings"
 
 	"ariga.io/atlas/sql/schema"
+
+	"github.com/hashicorp/hcl/v2"
 	"github.com/zclconf/go-cty/cty"
 	"github.com/zclconf/go-cty/cty/gocty"
 )
@@ -23,12 +25,14 @@ type (
 		Type      string
 		Attrs     []*Attr
 		Children  []*Resource
+		rang      *hcl.Range
 	}
 
 	// Attr is an attribute of a Resource.
 	Attr struct {
-		K string
-		V cty.Value
+		K    string
+		V    cty.Value
+		rang *hcl.Range
 	}
 
 	// Ref implements Value and represents a reference to another Resource.
@@ -379,6 +383,28 @@ func (a *Attr) Bools() (vs []bool, err error) {
 	return vs, nil
 }
 
+// SetRange sets the range of this attribute.
+func (a *Attr) SetRange(p *hcl.Range) {
+	a.rang = p
+}
+
+// Range returns the attribute range on the
+// file, or nil if it is not set.
+func (a *Attr) Range() *hcl.Range {
+	return a.rang
+}
+
+// SetRange sets the range of this resource.
+func (r *Resource) SetRange(p *hcl.Range) {
+	r.rang = p
+}
+
+// Range returns the resource range on the
+// file, or nil if it is not set.
+func (r *Resource) Range() *hcl.Range {
+	return r.rang
+}
+
 // Resource returns the first child Resource by its type and reports whether it was found.
 func (r *Resource) Resource(t string) (*Resource, bool) {
 	if r == nil {
diff --git a/schemahcl/stdlib.go b/schemahcl/stdlib.go
index e247d4e3..cfccd017 100644
--- a/schemahcl/stdlib.go
+++ b/schemahcl/stdlib.go
@@ -261,7 +261,8 @@ var (
 		Params: []function.Parameter{
 			{Name: "def", Type: cty.String, AllowNull: false},
 		},
-		Type: function.StaticReturnType(ctyRawExpr),
+		Type:        function.StaticReturnType(ctyRawExpr),
+		Description: "sql is a stub function for raw expressions.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			x := args[0].AsString()
 			if len(x) == 0 {
@@ -287,7 +288,8 @@ var (
 				Type: cty.String,
 			},
 		},
-		Type: function.StaticReturnType(cty.String),
+		Type:        function.StaticReturnType(cty.String),
+		Description: "urlqueryset sets the query parameter for the URL.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			u, err := url.Parse(args[0].AsString())
 			if err != nil {
@@ -316,7 +318,8 @@ var (
 			Type:      cty.String,
 			AllowNull: true,
 		},
-		Type: function.StaticReturnType(cty.String),
+		Type:        function.StaticReturnType(cty.String),
+		Description: "urluserinfo sets the user for the URL.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			u, err := url.Parse(args[0].AsString())
 			if err != nil {
@@ -343,7 +346,8 @@ var (
 				Type: cty.String,
 			},
 		},
-		Type: function.StaticReturnType(cty.String),
+		Type:        function.StaticReturnType(cty.String),
+		Description: "urlsetpath sets the path for the URL.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			u, err := url.Parse(args[0].AsString())
 			if err != nil {
@@ -361,7 +365,8 @@ var (
 				Type: cty.String,
 			},
 		},
-		Type: function.StaticReturnType(cty.String),
+		Type:        function.StaticReturnType(cty.String),
+		Description: "urlescape escapes the string so it can be safely placed inside a URL query.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			u := url.QueryEscape(args[0].AsString())
 			return cty.StringVal(u), nil
@@ -378,6 +383,7 @@ var (
 		Type: func(args []cty.Value) (cty.Type, error) {
 			return args[0].Type(), nil
 		},
+		Description: "print prints the value to stdout, and returns the value.",
 		Impl: func(args []cty.Value, _ cty.Type) (cty.Value, error) {
 			switch args[0].Type() {
 			case cty.String:
diff --git a/sql/internal/specutil/convert.go b/sql/internal/specutil/convert.go
index def6de8f..7d47ab5b 100644
--- a/sql/internal/specutil/convert.go
+++ b/sql/internal/specutil/convert.go
@@ -1141,7 +1141,7 @@ func findT[T schema.Object](sch *schema.Schema, qualifier, name string, findT fu
 	case 0:
 		err = fmt.Errorf("referenced %s %q not found", typeName(t), name)
 	default:
-		err = fmt.Errorf("multiple refrences %ss found for %q", typeName(t), name)
+		err = fmt.Errorf("multiple reference %ss found for %q", typeName(t), name)
 	}
 	return
 }
diff --git a/sql/internal/sqlx/sqlx.go b/sql/internal/sqlx/sqlx.go
index ac16a606..cedec817 100644
--- a/sql/internal/sqlx/sqlx.go
+++ b/sql/internal/sqlx/sqlx.go
@@ -12,6 +12,7 @@ import (
 	"fmt"
 	"io"
 	"reflect"
+	"slices"
 	"strconv"
 	"strings"
 	"unicode"
@@ -68,7 +69,7 @@ func ScanOne(rows *sql.Rows, dest ...any) error {
 	if err := rows.Scan(dest...); err != nil {
 		return err
 	}
-	return rows.Close()
+	return rows.Err()
 }
 
 // ScanNullBool scans one sql.NullBool record and closes the rows at the end.
@@ -223,20 +224,27 @@ func ValuesEqual(v1, v2 []string) bool {
 
 // ModeInspectSchema returns the InspectMode or its default.
 func ModeInspectSchema(o *schema.InspectOptions) schema.InspectMode {
-	if o == nil || o.Mode == 0 {
-		return schema.InspectSchemas | schema.InspectTables | schema.InspectViews | schema.InspectFuncs |
-			schema.InspectTypes | schema.InspectObjects | schema.InspectTriggers
+	if o != nil && o.Mode != 0 {
+		return o.Mode
 	}
-	return o.Mode
+	return modeSchemaOrAll(V(o).Exclude, "*")
 }
 
 // ModeInspectRealm returns the InspectMode or its default.
 func ModeInspectRealm(o *schema.InspectRealmOption) schema.InspectMode {
-	if o == nil || o.Mode == 0 {
-		return schema.InspectSchemas | schema.InspectTables | schema.InspectViews | schema.InspectFuncs |
-			schema.InspectTypes | schema.InspectObjects | schema.InspectTriggers
+	if o != nil && o.Mode != 0 {
+		return o.Mode
 	}
-	return o.Mode
+	return modeSchemaOrAll(V(o).Exclude, "*.*")
+}
+
+// modeSchemaOrAll returns the inspect mode based on the exclude patterns.
+func modeSchemaOrAll(exclude []string, match string) schema.InspectMode {
+	if slices.Contains(exclude, match) {
+		return schema.InspectSchemas
+	}
+	return schema.InspectSchemas | schema.InspectTables | schema.InspectViews | schema.InspectFuncs |
+		schema.InspectTypes | schema.InspectObjects | schema.InspectTriggers
 }
 
 // A Builder provides a syntactic sugar API for writing SQL statements.
diff --git a/sql/migrate/lex.go b/sql/migrate/lex.go
index 775aea59..c8262199 100644
--- a/sql/migrate/lex.go
+++ b/sql/migrate/lex.go
@@ -106,6 +106,12 @@ type (
 		MatchBeginAtomic bool
 		// MatchDollarQuote enables the PostgreSQL dollar-quoted string syntax.
 		MatchDollarQuote bool
+		// BackslashEscapes enables backslash-escaped strings. By default, only MySQL/MariaDB uses backslash as
+		// an escape character.  https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html#sqlmode_no_backslash_escapes
+		BackslashEscapes bool
+		// EscapedStringExt enables the supported for PG extension for escaped strings and adopted by its flavors.
+		// See: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE.
+		EscapedStringExt bool
 	}
 )
 
@@ -262,12 +268,15 @@ func (s *Scanner) addPos(p int) {
 }
 
 func (s *Scanner) skipQuote(quote rune) error {
-	pos := s.pos
+	var (
+		pos     = s.pos
+		escaped = s.BackslashEscapes || s.EscapedStringExt && s.pos > 0 && (s.input[s.pos-1] == 'E' || s.input[s.pos-1] == 'e')
+	)
 	for {
 		switch r := s.next(); {
 		case r == eos:
 			return s.error(pos, "unclosed quote %q", quote)
-		case r == '\\':
+		case r == '\\' && escaped:
 			s.next()
 		case r == quote:
 			return nil
diff --git a/sql/migrate/migrate.go b/sql/migrate/migrate.go
index 5b7cb625..0eccb8dc 100644
--- a/sql/migrate/migrate.go
+++ b/sql/migrate/migrate.go
@@ -783,7 +783,9 @@ func (e *Executor) Execute(ctx context.Context, m File) (err error) {
 	}
 	stmts, err := e.fileStmts(m)
 	if err != nil {
-		return fmt.Errorf("sql/migrate: scanning statements from %q: %w", m.Name(), err)
+		err = fmt.Errorf("sql/migrate: scanning statements from %q: %w", m.Name(), err)
+		e.log.Log(LogError{Error: err})
+		return err
 	}
 	// Create checksums for the statements.
 	var (
diff --git a/sql/mysql/driver.go b/sql/mysql/driver.go
index d4ab12e8..bf437d16 100644
--- a/sql/mysql/driver.go
+++ b/sql/mysql/driver.go
@@ -269,7 +269,8 @@ func (*Driver) StmtBuilder(opts migrate.PlanOptions) *sqlx.Builder {
 func (*Driver) ScanStmts(input string) ([]*migrate.Stmt, error) {
 	return (&migrate.Scanner{
 		ScannerOptions: migrate.ScannerOptions{
-			MatchBegin: true,
+			MatchBegin:       true,
+			BackslashEscapes: true,
 			// The following are not support by MySQL/MariaDB.
 			MatchBeginAtomic: false,
 			MatchDollarQuote: false,
diff --git a/sql/mysql/inspect.go b/sql/mysql/inspect.go
index a682f22f..e137a121 100644
--- a/sql/mysql/inspect.go
+++ b/sql/mysql/inspect.go
@@ -246,7 +246,7 @@ func (i *inspect) tables(ctx context.Context, realm *schema.Realm, opts *schema.
 			})
 		}
 	}
-	return rows.Close()
+	return rows.Err()
 }
 
 // columns queries and appends the columns of the given table.
diff --git a/sql/postgres/driver.go b/sql/postgres/driver.go
index 5800b5c5..91dec5b0 100644
--- a/sql/postgres/driver.go
+++ b/sql/postgres/driver.go
@@ -347,6 +347,7 @@ func (*Driver) ScanStmts(input string) ([]*migrate.Stmt, error) {
 			MatchBegin:       true,
 			MatchBeginAtomic: true,
 			MatchDollarQuote: true,
+			EscapedStringExt: true,
 		},
 	}).Scan(input)
 }
diff --git a/sql/postgres/inspect.go b/sql/postgres/inspect.go
index b0d88d80..a4c0967d 100644
--- a/sql/postgres/inspect.go
+++ b/sql/postgres/inspect.go
@@ -261,7 +261,7 @@ func (i *inspect) tables(ctx context.Context, realm *schema.Realm, opts *schema.
 			})
 		}
 	}
-	return rows.Close()
+	return rows.Err()
 }
 
 // columns queries and appends the columns of the given table.
@@ -280,7 +280,7 @@ func (i *inspect) columns(ctx context.Context, s *schema.Schema) error {
 			return fmt.Errorf("postgres: %w", err)
 		}
 	}
-	return rows.Close()
+	return rows.Err()
 }
 
 // addColumn scans the current row and adds a new column from it to the scope (table or view).
diff --git a/sql/postgres/migrate.go b/sql/postgres/migrate.go
index 1948958e..fe8b5a65 100644
--- a/sql/postgres/migrate.go
+++ b/sql/postgres/migrate.go
@@ -851,9 +851,8 @@ func (s *state) tableComment(src schema.Change, t *schema.Table, to, from string
 }
 
 func (s *state) columnComment(src schema.Change, t *schema.Table, c *schema.Column, to, from string) *migrate.Change {
-	b := s.Build("COMMENT ON COLUMN").Table(t)
-	b.WriteByte('.')
-	b.Ident(c.Name).P("IS")
+	b := s.Build("COMMENT ON COLUMN").TableResource(t, c)
+	b.P("IS")
 	return &migrate.Change{
 		Cmd:     b.Clone().P(quote(to)).String(),
 		Source:  src,
diff --git a/sql/sqlite/migrate.go b/sql/sqlite/migrate.go
index fc838f0e..1badb9bf 100644
--- a/sql/sqlite/migrate.go
+++ b/sql/sqlite/migrate.go
@@ -542,7 +542,8 @@ func (s *state) tableSeq(ctx context.Context, add *schema.AddTable) error {
 		})
 	}
 	if rows != nil {
-		return rows.Close()
+		rows.Close()
+		return rows.Err()
 	}
 	return nil
 }


Test patch:
diff --git a/cmd/atlas/internal/cmdext/cmdext_test.go b/cmd/atlas/internal/cmdext/cmdext_test.go
index 89e33e77..d200eb7a 100644
--- a/cmd/atlas/internal/cmdext/cmdext_test.go
+++ b/cmd/atlas/internal/cmdext/cmdext_test.go
@@ -316,6 +316,7 @@ schema = data.hcl_schema.a8m.url
 		// as they are defined on the data source.
 	})
 	require.NoError(t, err)
+	require.Equal(t, "a8m", sr.Schema)
 	realm, err := sr.ReadState(ctx)
 	require.NoError(t, err)
 	buf, err := drv.MarshalSpec(realm)
@@ -341,6 +342,7 @@ schema "a8m" {
 		// as they are defined on the data source.
 	})
 	require.NoError(t, err)
+	require.Empty(t, sr.Schema)
 	realm, err = sr.ReadState(ctx)
 	require.NoError(t, err)
 	buf, err = drv.MarshalSpec(realm)
diff --git a/cmd/atlas/internal/cmdlog/cmdlog_test.go b/cmd/atlas/internal/cmdlog/cmdlog_test.go
index 68257d6e..36a7ebd7 100644
--- a/cmd/atlas/internal/cmdlog/cmdlog_test.go
+++ b/cmd/atlas/internal/cmdlog/cmdlog_test.go
@@ -617,4 +617,17 @@ func TestMigrateApply(t *testing.T) {
   -- 3 checks ok, 1 failure
   -- 2 sql statements
 `, b.String())
+
+	// Error during plan stage.
+	b.Reset()
+	log.Applied = nil
+	log.Error = `sql/migrate: scanning statements from "20240116000003.sql": 5:115: unclosed quote '\''`
+	require.NoError(t, cmdlog.MigrateApplyTemplate.Execute(&b, log))
+	require.Equal(t, `Migrating to version 20240116000003 from 20240116000001 (2 migrations in total):
+
+    sql/migrate: scanning statements from "20240116000003.sql": 5:115: unclosed quote '\''
+
+  -------------------------
+  -- 10ms
+`, b.String())
 }
diff --git a/schemahcl/schemahcl_test.go b/schemahcl/schemahcl_test.go
index b1fe830a..0bb30e52 100644
--- a/schemahcl/schemahcl_test.go
+++ b/schemahcl/schemahcl_test.go
@@ -1072,3 +1072,30 @@ bar "b1" {
 		Ref:  &Ref{V: "$foo.f1"},
 	}, doc.Bar[0])
 }
+
+func Test_WithPos(t *testing.T) {
+	var (
+		doc struct {
+			DefaultExtension
+		}
+		b = []byte(`
+foo {}
+foo {
+  bar {
+    baz = 1
+  }
+}
+baz = 1
+`)
+	)
+	require.NoError(t, New(WithPos()).EvalBytes(b, &doc, nil))
+	at, ok := doc.Extra.Attr("baz")
+	require.True(t, ok)
+	require.Equal(t, 8, at.Range().Start.Line)
+	rs := doc.Extra.Resources("foo")
+	require.Len(t, rs, 2)
+	require.Equal(t, 2, rs[0].Range().Start.Line)
+	require.Equal(t, 3, rs[1].Range().Start.Line)
+	require.Equal(t, 4, rs[1].Children[0].Range().Start.Line)
+	require.Equal(t, 5, rs[1].Children[0].Attrs[0].Range().Start.Line)
+}
diff --git a/sql/internal/sqlx/sqlx_test.go b/sql/internal/sqlx/sqlx_test.go
index c7fac7fc..d8f0073b 100644
--- a/sql/internal/sqlx/sqlx_test.go
+++ b/sql/internal/sqlx/sqlx_test.go
@@ -26,6 +26,17 @@ func TestModeInspectRealm(t *testing.T) {
 	m = ModeInspectRealm(&schema.InspectRealmOption{Mode: schema.InspectSchemas})
 	require.True(t, m.Is(schema.InspectSchemas))
 	require.False(t, m.Is(schema.InspectTables))
+
+	m = ModeInspectRealm(&schema.InspectRealmOption{Exclude: []string{"*.*"}})
+	require.Equal(t, schema.InspectSchemas, m)
+	m = ModeInspectRealm(&schema.InspectRealmOption{Exclude: []string{"*"}})
+	require.NotEqual(t, schema.InspectSchemas, m)
+	require.True(t, m.Is(schema.InspectSchemas))
+	require.True(t, m.Is(schema.InspectTables))
+	m = ModeInspectRealm(&schema.InspectRealmOption{Mode: schema.InspectFuncs, Exclude: []string{"*.*"}})
+	require.NotEqual(t, schema.InspectSchemas, m)
+	require.True(t, m.Is(schema.InspectFuncs))
+	require.False(t, m.Is(schema.InspectTables))
 }
 
 func TestModeInspectSchema(t *testing.T) {
@@ -40,6 +51,17 @@ func TestModeInspectSchema(t *testing.T) {
 	m = ModeInspectSchema(&schema.InspectOptions{Mode: schema.InspectSchemas})
 	require.True(t, m.Is(schema.InspectSchemas))
 	require.False(t, m.Is(schema.InspectTables))
+
+	m = ModeInspectSchema(&schema.InspectOptions{Exclude: []string{"*"}})
+	require.Equal(t, schema.InspectSchemas, m)
+	m = ModeInspectSchema(&schema.InspectOptions{Exclude: []string{"*.*"}})
+	require.NotEqual(t, schema.InspectSchemas, m)
+	require.True(t, m.Is(schema.InspectSchemas))
+	require.True(t, m.Is(schema.InspectTables))
+	m = ModeInspectSchema(&schema.InspectOptions{Mode: schema.InspectFuncs, Exclude: []string{"*"}})
+	require.NotEqual(t, schema.InspectSchemas, m)
+	require.True(t, m.Is(schema.InspectFuncs))
+	require.False(t, m.Is(schema.InspectTables))
 }
 
 func TestBuilder(t *testing.T) {
diff --git a/sql/migrate/lex_test.go b/sql/migrate/lex_test.go
index 79e8ee43..efd21260 100644
--- a/sql/migrate/lex_test.go
+++ b/sql/migrate/lex_test.go
@@ -49,6 +49,42 @@ func TestScanner_StmtsGroup(t *testing.T) {
 	}
 }
 
+func TestScanner_EscapedStrings(t *testing.T) {
+	path := filepath.Join("testdata", "lexescaped")
+	dir, err := NewLocalDir(path)
+	require.NoError(t, err)
+	files, err := dir.Files()
+	require.NoError(t, err)
+	require.Len(t, files, 2, "tests should be updated")
+	scan := &Scanner{}
+	scan.BackslashEscapes = true
+	stmts, err := scan.Scan(string(files[0].Bytes()))
+	require.NoError(t, err)
+	buf, err := os.ReadFile(filepath.Join(path, files[0].Name()+".golden"))
+	require.NoError(t, err)
+	got := make([]string, len(stmts))
+	for i, s := range stmts {
+		got[i] = s.Text
+	}
+	require.Equalf(t, string(buf), strings.Join(got, "\n-- end --\n"), "mismatched statements in file %q", files[0].Name())
+	_, err = scan.Scan(string(files[1].Bytes()))
+	require.EqualError(t, err, `4:40: unclosed quote '\''`, "escaped strings conflicts with standard strings")
+
+	scan.BackslashEscapes = false
+	scan.EscapedStringExt = true
+	stmts, err = scan.Scan(string(files[0].Bytes()))
+	require.EqualError(t, err, `4:42: unclosed quote '\''`, "disabled escaped strings should fail parse of escaped strings without the extension")
+	stmts, err = scan.Scan(string(files[1].Bytes()))
+	require.NoError(t, err)
+	buf, err = os.ReadFile(filepath.Join(path, files[1].Name()+".golden"))
+	require.NoError(t, err)
+	got = make([]string, len(stmts))
+	for i, s := range stmts {
+		got[i] = s.Text
+	}
+	require.Equalf(t, string(buf), strings.Join(got, "\n-- end --\n"), "mismatched statements in file %q", files[1].Name())
+}
+
 func TestLocalFile_StmtDecls(t *testing.T) {
 	f := `cmd0;
 -- test
diff --git a/sql/migrate/testdata/lexescaped/1.my.sql b/sql/migrate/testdata/lexescaped/1.my.sql
new file mode 100644
index 00000000..06fcd44d
--- /dev/null
+++ b/sql/migrate/testdata/lexescaped/1.my.sql
@@ -0,0 +1,4 @@
+create table t (c text default '\\');
+create table t (c text default "\\");
+create table t (c text default "\"");
+create table t (c text default "\"" + '\'');
diff --git a/sql/migrate/testdata/lexescaped/1.my.sql.golden b/sql/migrate/testdata/lexescaped/1.my.sql.golden
new file mode 100644
index 00000000..0321e001
--- /dev/null
+++ b/sql/migrate/testdata/lexescaped/1.my.sql.golden
@@ -0,0 +1,7 @@
+create table t (c text default '\\');
+-- end --
+create table t (c text default "\\");
+-- end --
+create table t (c text default "\"");
+-- end --
+create table t (c text default "\"" + '\'');
\ No newline at end of file
diff --git a/sql/migrate/testdata/lexescaped/2.pg.sql b/sql/migrate/testdata/lexescaped/2.pg.sql
new file mode 100644
index 00000000..5670cbe6
--- /dev/null
+++ b/sql/migrate/testdata/lexescaped/2.pg.sql
@@ -0,0 +1,4 @@
+create table t1 (c text default '\');
+create table t1 (c text default E'\\');
+create table t1 (c text default '\A\');
+create table t1 (c text default e'\\A\\');
\ No newline at end of file
diff --git a/sql/migrate/testdata/lexescaped/2.pg.sql.golden b/sql/migrate/testdata/lexescaped/2.pg.sql.golden
new file mode 100644
index 00000000..2de61fa1
--- /dev/null
+++ b/sql/migrate/testdata/lexescaped/2.pg.sql.golden
@@ -0,0 +1,7 @@
+create table t1 (c text default '\');
+-- end --
+create table t1 (c text default E'\\');
+-- end --
+create table t1 (c text default '\A\');
+-- end --
+create table t1 (c text default e'\\A\\');
\ No newline at end of file
diff --git a/sql/postgres/migrate_test.go b/sql/postgres/migrate_test.go
index 7ba9db38..1f5d9df9 100644
--- a/sql/postgres/migrate_test.go
+++ b/sql/postgres/migrate_test.go
@@ -856,12 +856,12 @@ func TestPlanChanges(t *testing.T) {
 						Reverse: `DROP INDEX "nulls_not_distinct"`,
 					},
 					{
-						Cmd:     `COMMENT ON COLUMN "users" ."name" IS 'foo'`,
-						Reverse: `COMMENT ON COLUMN "users" ."name" IS ''`,
+						Cmd:     `COMMENT ON COLUMN "users"."name" IS 'foo'`,
+						Reverse: `COMMENT ON COLUMN "users"."name" IS ''`,
 					},
 					{
-						Cmd:     `COMMENT ON COLUMN "users" ."last" IS 'bar'`,
-						Reverse: `COMMENT ON COLUMN "users" ."last" IS ''`,
+						Cmd:     `COMMENT ON COLUMN "users"."last" IS 'bar'`,
+						Reverse: `COMMENT ON COLUMN "users"."last" IS ''`,
 					},
 					{
 						Cmd:     `COMMENT ON INDEX "id_key" IS 'comment'`,
@@ -903,8 +903,8 @@ func TestPlanChanges(t *testing.T) {
 						Reverse: `ALTER TABLE "users" ALTER COLUMN "id" SET GENERATED BY DEFAULT SET START WITH 1 SET INCREMENT BY 1 RESTART, ADD COLUMN "name" character varying NOT NULL`,
 					},
 					{
-						Cmd:     `COMMENT ON COLUMN "users" ."id" IS ''`,
-						Reverse: `COMMENT ON COLUMN "users" ."id" IS 'comment'`,
+						Cmd:     `COMMENT ON COLUMN "users"."id" IS ''`,
+						Reverse: `COMMENT ON COLUMN "users"."id" IS 'comment'`,
 					},
 				},
 			},
@@ -1293,7 +1293,7 @@ func TestPlanChanges(t *testing.T) {
 				Transactional: true,
 				Changes: []*migrate.Change{
 					{Cmd: `ALTER TYPE "public"."state" ADD VALUE 'unknown'`},
-					{Cmd: `COMMENT ON COLUMN "public"."users" ."state" IS ''`, Reverse: `COMMENT ON COLUMN "public"."users" ."state" IS 'foo'`},
+					{Cmd: `COMMENT ON COLUMN "public"."users"."state" IS ''`, Reverse: `COMMENT ON COLUMN "public"."users"."state" IS 'foo'`},
 				},
 			},
 		},
@@ -1323,7 +1323,7 @@ func TestPlanChanges(t *testing.T) {
 				Reversible:    true,
 				Transactional: true,
 				Changes: []*migrate.Change{
-					{Cmd: `COMMENT ON COLUMN "users" ."state" IS 'foo'`, Reverse: `COMMENT ON COLUMN "users" ."state" IS 'bar'`},
+					{Cmd: `COMMENT ON COLUMN "users"."state" IS 'foo'`, Reverse: `COMMENT ON COLUMN "users"."state" IS 'bar'`},
 				},
 			},
 		},