Repository: ariga/atlas
Pull request #1626 (2023-05-03 15:35:07)

web/projects-num-update
Update projects amount;
Updated footer;


Patch:
diff --git a/cmd/atlas/internal/cmdapi/cmdapi.go b/cmd/atlas/internal/cmdapi/cmdapi.go
index db891864..86dc0a85 100644
--- a/cmd/atlas/internal/cmdapi/cmdapi.go
+++ b/cmd/atlas/internal/cmdapi/cmdapi.go
@@ -440,7 +440,11 @@ func stateReader(ctx context.Context, config *stateReaderConfig) (*stateReadClos
 			if err != nil {
 				return nil, err
 			}
-			return &stateReadCloser{StateReader: sr}, nil
+			rc := &stateReadCloser{StateReader: sr}
+			if config.dev != nil && config.dev.URL.Schema != "" {
+				rc.schema = config.dev.URL.Schema
+			}
+			return rc, nil
 		}
 		// All other schemes are database (or docker) connections.
 		c, err := sqlclient.Open(ctx, config.urls[0]) // call to selectScheme already checks for len > 0
diff --git a/cmd/atlas/internal/cmdapi/project.go b/cmd/atlas/internal/cmdapi/project.go
index 1d629e71..a41a06dd 100644
--- a/cmd/atlas/internal/cmdapi/project.go
+++ b/cmd/atlas/internal/cmdapi/project.go
@@ -256,6 +256,10 @@ func (d *Diff) Extend(global *Diff) *Diff {
 
 // Options converts the diff policy into options.
 func (d *Diff) Options() (opts []schema.DiffOption) {
+	// Per-driver configuration.
+	opts = append(opts, func(opts *schema.DiffOptions) {
+		opts.Extra = d.DefaultExtension
+	})
 	if d.SkipChanges == nil {
 		return
 	}
diff --git a/cmd/atlas/internal/lint/lint.go b/cmd/atlas/internal/lint/lint.go
index 9e369963..1b8643c0 100644
--- a/cmd/atlas/internal/lint/lint.go
+++ b/cmd/atlas/internal/lint/lint.go
@@ -191,13 +191,13 @@ func (d *DevLoader) LoadChanges(ctx context.Context, base, files []migrate.File)
 	}()
 	// Bring the dev environment to the base point.
 	for _, f := range base {
-		stmt, err := f.Stmts()
+		stmt, err := f.StmtDecls()
 		if err != nil {
 			return nil, &FileError{File: f.Name(), Err: fmt.Errorf("scanning statements: %w", err)}
 		}
 		for _, s := range stmt {
-			if _, err := d.Dev.ExecContext(ctx, s); err != nil {
-				return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %q: %w", s, err)}
+			if _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {
+				return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %w", err), Pos: s.Pos}
 			}
 		}
 	}
@@ -221,7 +221,7 @@ func (d *DevLoader) LoadChanges(ctx context.Context, base, files []migrate.File)
 		start := current
 		for _, s := range stmts {
 			if _, err := d.Dev.ExecContext(ctx, s.Text); err != nil {
-				return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %w", err)}
+				return nil, &FileError{File: f.Name(), Err: fmt.Errorf("executing statement: %w", err), Pos: s.Pos}
 			}
 			target, err := d.inspect(ctx)
 			if err != nil {
@@ -288,7 +288,8 @@ func (d *DevLoader) lock(ctx context.Context) (schema.UnlockFunc, error) {
 // FileError represents an error that occurred while processing a file.
 type FileError struct {
 	File string
-	Err  error
+	Err  error // Atlas or database error.
+	Pos  int   // Position error, if known.
 }
 
 func (e FileError) Error() string { return e.Err.Error() }
diff --git a/doc/website/package-lock.json b/doc/website/package-lock.json
index 6b5ca173..1f92032e 100644
--- a/doc/website/package-lock.json
+++ b/doc/website/package-lock.json
@@ -8,7 +8,7 @@
       "name": "website",
       "version": "0.0.0",
       "dependencies": {
-        "@ariga/atlas-website": "0.0.11",
+        "@ariga/atlas-website": "0.0.12",
         "@docusaurus/core": "^2.0.0-rc.1",
         "@docusaurus/plugin-client-redirects": "^2.0.0-rc.1",
         "@docusaurus/preset-classic": "^2.0.0-rc.1",
@@ -286,9 +286,9 @@
       }
     },
     "node_modules/@ariga/atlas-website": {
-      "version": "0.0.11",
-      "resolved": "https://registry.npmjs.org/@ariga/atlas-website/-/atlas-website-0.0.11.tgz",
-      "integrity": "sha512-DxVOhg0DLQsgHNPua0T5VA2uakj1jzvmaHap7NmJFHYR7xe/0MjmRbH83e+4B5cjqPgF/+7RgF+C7nn1bylW2w==",
+      "version": "0.0.12",
+      "resolved": "https://registry.npmjs.org/@ariga/atlas-website/-/atlas-website-0.0.12.tgz",
+      "integrity": "sha512-3PwBc1c1oW9YxAFmMXFJVvrdoLkkL+QuH1aHNgtSEMbVLYWfS4Rdnd9U0GIjvWujVgFFCeWh5EuURHHfHuhccg==",
       "dependencies": {
         "@amplitude/analytics-browser": "^1.9.4",
         "@types/amplitude-js": "^8.16.2",
@@ -311,7 +311,8 @@
         "replace-in-file": "^6.3.5",
         "tailwind-scrollbar": "^2.1.0",
         "tailwindcss": "^3.2.6",
-        "vite-plugin-dts": "^1.7.1"
+        "vite-plugin-dts": "^1.7.1",
+        "vite-plugin-svgr": "^3.2.0"
       },
       "peerDependencies": {
         "react": "^17.0.1",
@@ -14820,6 +14821,233 @@
         "vite": ">=2.9.0"
       }
     },
+    "node_modules/vite-plugin-svgr": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-3.2.0.tgz",
+      "integrity": "sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==",
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.2",
+        "@svgr/core": "^7.0.0",
+        "@svgr/plugin-jsx": "^7.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^2.6.0 || 3 || 4"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-add-jsx-attribute": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-7.0.0.tgz",
+      "integrity": "sha512-khWbXesWIP9v8HuKCl2NU2HNAyqpSQ/vkIl36Nbn4HIwEYSRWL0H7Gs6idJdha2DkpFDWlsqMELvoCE8lfFY6Q==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-remove-jsx-attribute": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz",
+      "integrity": "sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz",
+      "integrity": "sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-7.0.0.tgz",
+      "integrity": "sha512-i6MaAqIZXDOJeikJuzocByBf8zO+meLwfQ/qMHIjCcvpnfvWf82PFvredEZElErB5glQFJa2KVKk8N2xV6tRRA==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-svg-dynamic-title": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-7.0.0.tgz",
+      "integrity": "sha512-BoVSh6ge3SLLpKC0pmmN9DFlqgFy4NxNgdZNLPNJWBUU7TQpDWeBuyVuDW88iXydb5Cv0ReC+ffa5h3VrKfk1w==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-svg-em-dimensions": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-7.0.0.tgz",
+      "integrity": "sha512-tNDcBa+hYn0gO+GkP/AuNKdVtMufVhU9fdzu+vUQsR18RIJ9RWe7h/pSBY338RO08wArntwbDk5WhQBmhf2PaA==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-transform-react-native-svg": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-7.0.0.tgz",
+      "integrity": "sha512-qw54u8ljCJYL2KtBOjI5z7Nzg8LnSvQOP5hPKj77H4VQL4+HdKbAT5pnkkZLmHKYwzsIHSYKXxHouD8zZamCFQ==",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-plugin-transform-svg-component": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-7.0.0.tgz",
+      "integrity": "sha512-CcFECkDj98daOg9jE3Bh3uyD9kzevCAnZ+UtzG6+BQG/jOQ2OA3jHnX6iG4G1MCJkUQFnUvEv33NvQfqrb/F3A==",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/babel-preset": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-7.0.0.tgz",
+      "integrity": "sha512-EX/NHeFa30j5UjldQGVQikuuQNHUdGmbh9kEpBKofGUtF0GUPJ4T4rhoYiqDAOmBOxojyot36JIFiDUHUK1ilQ==",
+      "dependencies": {
+        "@svgr/babel-plugin-add-jsx-attribute": "^7.0.0",
+        "@svgr/babel-plugin-remove-jsx-attribute": "^7.0.0",
+        "@svgr/babel-plugin-remove-jsx-empty-expression": "^7.0.0",
+        "@svgr/babel-plugin-replace-jsx-attribute-value": "^7.0.0",
+        "@svgr/babel-plugin-svg-dynamic-title": "^7.0.0",
+        "@svgr/babel-plugin-svg-em-dimensions": "^7.0.0",
+        "@svgr/babel-plugin-transform-react-native-svg": "^7.0.0",
+        "@svgr/babel-plugin-transform-svg-component": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/core": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/core/-/core-7.0.0.tgz",
+      "integrity": "sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==",
+      "dependencies": {
+        "@babel/core": "^7.21.3",
+        "@svgr/babel-preset": "^7.0.0",
+        "camelcase": "^6.2.0",
+        "cosmiconfig": "^8.1.3"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/hast-util-to-babel-ast": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-7.0.0.tgz",
+      "integrity": "sha512-42Ej9sDDEmsJKjrfQ1PHmiDiHagh/u9AHO9QWbeNx4KmD9yS5d1XHmXUNINfUcykAU+4431Cn+k6Vn5mWBYimQ==",
+      "dependencies": {
+        "@babel/types": "^7.21.3",
+        "entities": "^4.4.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/@svgr/plugin-jsx": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-7.0.0.tgz",
+      "integrity": "sha512-SWlTpPQmBUtLKxXWgpv8syzqIU8XgFRvyhfkam2So8b3BE0OS0HPe5UfmlJ2KIC+a7dpuuYovPR2WAQuSyMoPw==",
+      "dependencies": {
+        "@babel/core": "^7.21.3",
+        "@svgr/babel-preset": "^7.0.0",
+        "@svgr/hast-util-to-babel-ast": "^7.0.0",
+        "svg-parser": "^2.0.4"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/gregberge"
+      }
+    },
+    "node_modules/vite-plugin-svgr/node_modules/cosmiconfig": {
+      "version": "8.1.3",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz",
+      "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==",
+      "dependencies": {
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/d-fischer"
+      }
+    },
     "node_modules/wait-on": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
@@ -15810,9 +16038,9 @@
       }
     },
     "@ariga/atlas-website": {
-      "version": "0.0.11",
-      "resolved": "https://registry.npmjs.org/@ariga/atlas-website/-/atlas-website-0.0.11.tgz",
-      "integrity": "sha512-DxVOhg0DLQsgHNPua0T5VA2uakj1jzvmaHap7NmJFHYR7xe/0MjmRbH83e+4B5cjqPgF/+7RgF+C7nn1bylW2w==",
+      "version": "0.0.12",
+      "resolved": "https://registry.npmjs.org/@ariga/atlas-website/-/atlas-website-0.0.12.tgz",
+      "integrity": "sha512-3PwBc1c1oW9YxAFmMXFJVvrdoLkkL+QuH1aHNgtSEMbVLYWfS4Rdnd9U0GIjvWujVgFFCeWh5EuURHHfHuhccg==",
       "requires": {
         "@amplitude/analytics-browser": "^1.9.4",
         "@types/amplitude-js": "^8.16.2",
@@ -15835,7 +16063,8 @@
         "replace-in-file": "^6.3.5",
         "tailwind-scrollbar": "^2.1.0",
         "tailwindcss": "^3.2.6",
-        "vite-plugin-dts": "^1.7.1"
+        "vite-plugin-dts": "^1.7.1",
+        "vite-plugin-svgr": "^3.2.0"
       }
     },
     "@babel/code-frame": {
@@ -26086,6 +26315,115 @@
         "ts-morph": "17.0.1"
       }
     },
+    "vite-plugin-svgr": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-3.2.0.tgz",
+      "integrity": "sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==",
+      "requires": {
+        "@rollup/pluginutils": "^5.0.2",
+        "@svgr/core": "^7.0.0",
+        "@svgr/plugin-jsx": "^7.0.0"
+      },
+      "dependencies": {
+        "@svgr/babel-plugin-add-jsx-attribute": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-7.0.0.tgz",
+          "integrity": "sha512-khWbXesWIP9v8HuKCl2NU2HNAyqpSQ/vkIl36Nbn4HIwEYSRWL0H7Gs6idJdha2DkpFDWlsqMELvoCE8lfFY6Q=="
+        },
+        "@svgr/babel-plugin-remove-jsx-attribute": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-7.0.0.tgz",
+          "integrity": "sha512-iiZaIvb3H/c7d3TH2HBeK91uI2rMhZNwnsIrvd7ZwGLkFw6mmunOCoVnjdYua662MqGFxlN9xTq4fv9hgR4VXQ=="
+        },
+        "@svgr/babel-plugin-remove-jsx-empty-expression": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-7.0.0.tgz",
+          "integrity": "sha512-sQQmyo+qegBx8DfFc04PFmIO1FP1MHI1/QEpzcIcclo5OAISsOJPW76ZIs0bDyO/DBSJEa/tDa1W26pVtt0FRw=="
+        },
+        "@svgr/babel-plugin-replace-jsx-attribute-value": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-7.0.0.tgz",
+          "integrity": "sha512-i6MaAqIZXDOJeikJuzocByBf8zO+meLwfQ/qMHIjCcvpnfvWf82PFvredEZElErB5glQFJa2KVKk8N2xV6tRRA=="
+        },
+        "@svgr/babel-plugin-svg-dynamic-title": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-7.0.0.tgz",
+          "integrity": "sha512-BoVSh6ge3SLLpKC0pmmN9DFlqgFy4NxNgdZNLPNJWBUU7TQpDWeBuyVuDW88iXydb5Cv0ReC+ffa5h3VrKfk1w=="
+        },
+        "@svgr/babel-plugin-svg-em-dimensions": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-7.0.0.tgz",
+          "integrity": "sha512-tNDcBa+hYn0gO+GkP/AuNKdVtMufVhU9fdzu+vUQsR18RIJ9RWe7h/pSBY338RO08wArntwbDk5WhQBmhf2PaA=="
+        },
+        "@svgr/babel-plugin-transform-react-native-svg": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-7.0.0.tgz",
+          "integrity": "sha512-qw54u8ljCJYL2KtBOjI5z7Nzg8LnSvQOP5hPKj77H4VQL4+HdKbAT5pnkkZLmHKYwzsIHSYKXxHouD8zZamCFQ=="
+        },
+        "@svgr/babel-plugin-transform-svg-component": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-7.0.0.tgz",
+          "integrity": "sha512-CcFECkDj98daOg9jE3Bh3uyD9kzevCAnZ+UtzG6+BQG/jOQ2OA3jHnX6iG4G1MCJkUQFnUvEv33NvQfqrb/F3A=="
+        },
+        "@svgr/babel-preset": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-7.0.0.tgz",
+          "integrity": "sha512-EX/NHeFa30j5UjldQGVQikuuQNHUdGmbh9kEpBKofGUtF0GUPJ4T4rhoYiqDAOmBOxojyot36JIFiDUHUK1ilQ==",
+          "requires": {
+            "@svgr/babel-plugin-add-jsx-attribute": "^7.0.0",
+            "@svgr/babel-plugin-remove-jsx-attribute": "^7.0.0",
+            "@svgr/babel-plugin-remove-jsx-empty-expression": "^7.0.0",
+            "@svgr/babel-plugin-replace-jsx-attribute-value": "^7.0.0",
+            "@svgr/babel-plugin-svg-dynamic-title": "^7.0.0",
+            "@svgr/babel-plugin-svg-em-dimensions": "^7.0.0",
+            "@svgr/babel-plugin-transform-react-native-svg": "^7.0.0",
+            "@svgr/babel-plugin-transform-svg-component": "^7.0.0"
+          }
+        },
+        "@svgr/core": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/core/-/core-7.0.0.tgz",
+          "integrity": "sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw==",
+          "requires": {
+            "@babel/core": "^7.21.3",
+            "@svgr/babel-preset": "^7.0.0",
+            "camelcase": "^6.2.0",
+            "cosmiconfig": "^8.1.3"
+          }
+        },
+        "@svgr/hast-util-to-babel-ast": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-7.0.0.tgz",
+          "integrity": "sha512-42Ej9sDDEmsJKjrfQ1PHmiDiHagh/u9AHO9QWbeNx4KmD9yS5d1XHmXUNINfUcykAU+4431Cn+k6Vn5mWBYimQ==",
+          "requires": {
+            "@babel/types": "^7.21.3",
+            "entities": "^4.4.0"
+          }
+        },
+        "@svgr/plugin-jsx": {
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-7.0.0.tgz",
+          "integrity": "sha512-SWlTpPQmBUtLKxXWgpv8syzqIU8XgFRvyhfkam2So8b3BE0OS0HPe5UfmlJ2KIC+a7dpuuYovPR2WAQuSyMoPw==",
+          "requires": {
+            "@babel/core": "^7.21.3",
+            "@svgr/babel-preset": "^7.0.0",
+            "@svgr/hast-util-to-babel-ast": "^7.0.0",
+            "svg-parser": "^2.0.4"
+          }
+        },
+        "cosmiconfig": {
+          "version": "8.1.3",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz",
+          "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==",
+          "requires": {
+            "import-fresh": "^3.2.1",
+            "js-yaml": "^4.1.0",
+            "parse-json": "^5.0.0",
+            "path-type": "^4.0.0"
+          }
+        }
+      }
+    },
     "wait-on": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
diff --git a/doc/website/package.json b/doc/website/package.json
index 56083ee5..b528a764 100644
--- a/doc/website/package.json
+++ b/doc/website/package.json
@@ -16,7 +16,7 @@
     "invalidate-cdn": "aws cloudfront create-invalidation --distribution-id E3VOJYSV9YO33D --paths \"/*\""
   },
   "dependencies": {
-    "@ariga/atlas-website": "0.0.11",
+    "@ariga/atlas-website": "0.0.12",
     "@docusaurus/core": "^2.0.0-rc.1",
     "@docusaurus/plugin-client-redirects": "^2.0.0-rc.1",
     "@docusaurus/preset-classic": "^2.0.0-rc.1",
diff --git a/sql/internal/sqlx/diff.go b/sql/internal/sqlx/diff.go
index 8f9d6a36..d92809c7 100644
--- a/sql/internal/sqlx/diff.go
+++ b/sql/internal/sqlx/diff.go
@@ -72,6 +72,12 @@ type (
 	TableFinder interface {
 		FindTable(*schema.Schema, string) (*schema.Table, error)
 	}
+
+	// ChangesAnnotator is an optional interface allows DiffDriver to annotate
+	// changes with additional driver-specific attributes before they are returned.
+	ChangesAnnotator interface {
+		AnnotateChanges([]schema.Change, *schema.DiffOptions) error
+	}
 )
 
 // RealmDiff implements the schema.Differ for Realm objects and returns a list of changes
@@ -104,13 +110,18 @@ func (d *Diff) RealmDiff(from, to *schema.Realm, options ...schema.DiffOption) (
 			changes = opts.AddOrSkip(changes, &schema.AddTable{T: t})
 		}
 	}
-	return changes, nil
+	return d.mayAnnotate(changes, opts)
 }
 
 // SchemaDiff implements the schema.Differ interface and returns a list of
 // changes that need to be applied in order to move from one state to the other.
-func (d *Diff) SchemaDiff(from, to *schema.Schema, opts ...schema.DiffOption) ([]schema.Change, error) {
-	return d.schemaDiff(from, to, schema.NewDiffOptions(opts...))
+func (d *Diff) SchemaDiff(from, to *schema.Schema, options ...schema.DiffOption) ([]schema.Change, error) {
+	opts := schema.NewDiffOptions(options...)
+	changes, err := d.schemaDiff(from, to, opts)
+	if err != nil {
+		return nil, err
+	}
+	return d.mayAnnotate(changes, opts)
 }
 
 func (d *Diff) schemaDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]schema.Change, error) {
@@ -160,11 +171,16 @@ func (d *Diff) schemaDiff(from, to *schema.Schema, opts *schema.DiffOptions) ([]
 
 // TableDiff implements the schema.TableDiffer interface and returns a list of
 // changes that need to be applied in order to move from one state to the other.
-func (d *Diff) TableDiff(from, to *schema.Table, opts ...schema.DiffOption) ([]schema.Change, error) {
+func (d *Diff) TableDiff(from, to *schema.Table, options ...schema.DiffOption) ([]schema.Change, error) {
+	opts := schema.NewDiffOptions(options...)
 	if from.Name != to.Name {
 		return nil, fmt.Errorf("mismatched table names: %q != %q", from.Name, to.Name)
 	}
-	return d.tableDiff(from, to, schema.NewDiffOptions(opts...))
+	changes, err := d.tableDiff(from, to, opts)
+	if err != nil {
+		return nil, err
+	}
+	return d.mayAnnotate(changes, opts)
 }
 
 // tableDiff implements the table diffing but skips the table name check.
@@ -245,6 +261,16 @@ func (d *Diff) tableDiff(from, to *schema.Table, opts *schema.DiffOptions) ([]sc
 	return changes, nil
 }
 
+func (d *Diff) mayAnnotate(changes []schema.Change, opts *schema.DiffOptions) ([]schema.Change, error) {
+	r, ok := d.DiffDriver.(ChangesAnnotator)
+	if ok {
+		if err := r.AnnotateChanges(changes, opts); err != nil {
+			return nil, err
+		}
+	}
+	return changes, nil
+}
+
 // pkDiff returns the schema changes (if any) for migrating table
 // primary-key from current state to the desired state.
 func (d *Diff) pkDiff(from, to *schema.Table, opts *schema.DiffOptions) (changes []schema.Change) {
diff --git a/sql/postgres/diff.go b/sql/postgres/diff.go
index 86d8d669..aa275739 100644
--- a/sql/postgres/diff.go
+++ b/sql/postgres/diff.go
@@ -13,6 +13,7 @@ import (
 	"strings"
 	"unicode"
 
+	"ariga.io/atlas/schemahcl"
 	"ariga.io/atlas/sql/internal/sqlx"
 	"ariga.io/atlas/sql/schema"
 )
@@ -226,6 +227,48 @@ func (*diff) ReferenceChanged(from, to schema.ReferenceOption) bool {
 	return from != to
 }
 
+// DiffOptions defines PostgreSQL specific schema diffing process.
+type DiffOptions struct {
+	ConcurrentIndex struct {
+		Add  bool `spec:"add"`
+		Drop bool `spec:"drop"`
+	} `spec:"concurrent_index"`
+}
+
+// AnnotateChanges implements the sqlx.ChangeAnnotator interface.
+func (*diff) AnnotateChanges(changes []schema.Change, opts *schema.DiffOptions) error {
+	var extra DiffOptions
+	switch ex := opts.Extra.(type) {
+	case nil:
+		return nil
+	case schemahcl.DefaultExtension:
+		if err := ex.Extra.As(&extra); err != nil {
+			return err
+		}
+	default:
+		return fmt.Errorf("postgres: unexpected DiffOptions.Extra type %T", opts.Extra)
+	}
+	for _, c := range changes {
+		m, ok := c.(*schema.ModifyTable)
+		if !ok {
+			continue
+		}
+		for i := range m.Changes {
+			switch c := m.Changes[i].(type) {
+			case *schema.AddIndex:
+				if extra.ConcurrentIndex.Add {
+					c.Extra = append(c.Extra, &Concurrently{})
+				}
+			case *schema.DropIndex:
+				if extra.ConcurrentIndex.Drop {
+					c.Extra = append(c.Extra, &Concurrently{})
+				}
+			}
+		}
+	}
+	return nil
+}
+
 func (d *diff) typeChanged(from, to *schema.Column) (bool, error) {
 	fromT, toT := from.Type.Type, to.Type.Type
 	if fromT == nil || toT == nil {
diff --git a/sql/schema/migrate.go b/sql/schema/migrate.go
index 5132d558..e34ce247 100644
--- a/sql/schema/migrate.go
+++ b/sql/schema/migrate.go
@@ -290,6 +290,10 @@ type (
 	DiffOptions struct {
 		// SkipChanges defines a list of change types to skip.
 		SkipChanges []Change
+
+		// Extra defines per-driver configuration. If not
+		// nil, should be set to schemahcl.Extension.
+		Extra any // avoid circular dependency with schemahcl.
 	}
 
 	// DiffOption allows configuring the DiffOptions using functional options.


Test patch:
diff --git a/cmd/atlas/internal/cmdapi/project_test.go b/cmd/atlas/internal/cmdapi/project_test.go
index 4ef8e2d8..c07b9ffb 100644
--- a/cmd/atlas/internal/cmdapi/project_test.go
+++ b/cmd/atlas/internal/cmdapi/project_test.go
@@ -200,18 +200,18 @@ env {
 
 func TestDiff_Options(t *testing.T) {
 	d := &Diff{}
-	require.Len(t, d.Options(), 0)
+	require.Len(t, d.Options(), 1)
 	d.SkipChanges = &SkipChanges{}
-	require.Len(t, d.Options(), 0)
+	require.Len(t, d.Options(), 1)
 
 	d.SkipChanges = &SkipChanges{DropSchema: true}
-	require.Len(t, d.Options(), 1)
+	require.Len(t, d.Options(), 2)
 	opts := schema.NewDiffOptions(d.Options()...)
 	require.True(t, opts.Skipped(&schema.DropSchema{}))
 	require.False(t, opts.Skipped(&schema.DropTable{}))
 
 	d.SkipChanges = &SkipChanges{DropSchema: true, DropTable: true}
-	require.Len(t, d.Options(), 1)
+	require.Len(t, d.Options(), 2)
 	opts = schema.NewDiffOptions(d.Options()...)
 	require.True(t, opts.Skipped(&schema.DropSchema{}))
 	require.True(t, opts.Skipped(&schema.DropTable{}))
diff --git a/cmd/atlas/internal/lint/lint_test.go b/cmd/atlas/internal/lint/lint_test.go
index e90fdf72..fb7b0577 100644
--- a/cmd/atlas/internal/lint/lint_test.go
+++ b/cmd/atlas/internal/lint/lint_test.go
@@ -125,14 +125,23 @@ func TestDevLoader_LoadChanges(t *testing.T) {
 	require.NoError(t, err)
 	require.Empty(t, diff.Files)
 
+	diff, err = l.LoadChanges(ctx, []migrate.File{
+		testFile{name: "base.sql", content: "---\n\nCREATE INVALID users (id INT);\n"},
+	}, nil)
+	require.Error(t, err)
+	require.Nil(t, diff)
+	fr := err.(*lint.FileError)
+	require.Equal(t, `executing statement: near "INVALID": syntax error`, fr.Err.Error())
+	require.Equal(t, 5, fr.Pos)
+
 	base := []migrate.File{
-		testFile{name: "base.sql", content: "CREATE TABLE users (id INT)"},
+		testFile{name: "base.sql", content: "CREATE TABLE users (id INT);"},
 	}
 	files := []migrate.File{
-		testFile{name: "1.sql", content: "CREATE TABLE t1 (id INT)\nINSERT INTO t1 (id) VALUES (1)"},
-		testFile{name: "2.sql", content: "CREATE TABLE t2 (id INT)\nDROP TABLE users"},
-		testFile{name: "3.sql", content: "CREATE TABLE t3 (id INT)\nDROP TABLE t3"},
-		testFile{name: "4.sql", content: "ALTER TABLE t2 RENAME id TO oid"},
+		testFile{name: "1.sql", content: "CREATE TABLE t1 (id INT);\nINSERT INTO t1 (id) VALUES (1);"},
+		testFile{name: "2.sql", content: "CREATE TABLE t2 (id INT);\nDROP TABLE users;"},
+		testFile{name: "3.sql", content: "CREATE TABLE t3 (id INT);\nDROP TABLE t3;"},
+		testFile{name: "4.sql", content: "ALTER TABLE t2 RENAME id TO oid;"},
 	}
 	diff, err = l.LoadChanges(ctx, base, files)
 	require.NoError(t, err)
@@ -142,19 +151,19 @@ func TestDevLoader_LoadChanges(t *testing.T) {
 	require.Equal(t, files[0], diff.Files[0].File)
 	require.Len(t, diff.Files[0].Changes, 2)
 	require.Zero(t, diff.Files[0].Changes[0].Stmt.Pos)
-	require.Equal(t, "CREATE TABLE t1 (id INT)", diff.Files[0].Changes[0].Stmt.Text)
+	require.Equal(t, "CREATE TABLE t1 (id INT);", diff.Files[0].Changes[0].Stmt.Text)
 	require.IsType(t, (*schema.AddTable)(nil), diff.Files[0].Changes[0].Changes[0])
-	require.Equal(t, "INSERT INTO t1 (id) VALUES (1)", diff.Files[0].Changes[1].Stmt.Text)
+	require.Equal(t, "INSERT INTO t1 (id) VALUES (1);", diff.Files[0].Changes[1].Stmt.Text)
 	require.Empty(t, diff.Files[0].Changes[1].Changes)
 
 	// File 2.
 	require.Equal(t, files[1], diff.Files[1].File)
 	require.Len(t, diff.Files[1].Changes, 2)
 	require.Zero(t, diff.Files[1].Changes[0].Stmt.Pos)
-	require.Equal(t, "CREATE TABLE t2 (id INT)", diff.Files[1].Changes[0].Stmt.Text)
+	require.Equal(t, "CREATE TABLE t2 (id INT);", diff.Files[1].Changes[0].Stmt.Text)
 	require.IsType(t, (*schema.AddTable)(nil), diff.Files[1].Changes[0].Changes[0])
 	require.Zero(t, diff.Files[1].Changes[0].Stmt.Pos)
-	require.Equal(t, "DROP TABLE users", diff.Files[1].Changes[1].Stmt.Text)
+	require.Equal(t, "DROP TABLE users;", diff.Files[1].Changes[1].Stmt.Text)
 	require.IsType(t, (*schema.DropTable)(nil), diff.Files[1].Changes[1].Changes[0])
 
 	// File 3.
@@ -214,16 +223,9 @@ func (f testFile) Bytes() []byte {
 }
 
 func (f testFile) Stmts() ([]string, error) {
-	return strings.Split(string(f.Bytes()), "\n"), nil
+	return strings.Split(f.content, "\n"), nil
 }
 
 func (f testFile) StmtDecls() (stmts []*migrate.Stmt, err error) {
-	s, err := f.Stmts()
-	if err != nil {
-		return nil, err
-	}
-	for _, s := range s {
-		stmts = append(stmts, &migrate.Stmt{Text: s})
-	}
-	return
+	return migrate.Stmts(f.content)
 }
diff --git a/cmd/atlas/internal/lint/run_test.go b/cmd/atlas/internal/lint/run_test.go
index 826bfadc..3e04e04f 100644
--- a/cmd/atlas/internal/lint/run_test.go
+++ b/cmd/atlas/internal/lint/run_test.go
@@ -30,10 +30,10 @@ func TestRunner_Run(t *testing.T) {
 		Dev: c,
 		ChangeDetector: testDetector{
 			base: []migrate.File{
-				testFile{name: "1.sql", content: "CREATE TABLE users (id INT)"},
+				testFile{name: "1.sql", content: "CREATE TABLE users (id INT);"},
 			},
 			feat: []migrate.File{
-				testFile{name: "2.sql", content: "CREATE TABLE pets (id INT)\nDROP TABLE users"},
+				testFile{name: "2.sql", content: "CREATE TABLE pets (id INT);\nDROP TABLE users;"},
 			},
 		},
 		Analyzers: []sqlcheck.Analyzer{
@@ -50,8 +50,8 @@ func TestRunner_Run(t *testing.T) {
 	require.Len(t, passes, 1)
 	changes := passes[0].File.Changes
 	require.Len(t, changes, 2)
-	require.Equal(t, "CREATE TABLE pets (id INT)", changes[0].Stmt.Text)
-	require.Equal(t, "DROP TABLE users", changes[1].Stmt.Text)
+	require.Equal(t, "CREATE TABLE pets (id INT);", changes[0].Stmt.Text)
+	require.Equal(t, "DROP TABLE users;", changes[1].Stmt.Text)
 	require.Equal(t, `2.sql: Report 1:
 
 	L1: Diagnostic 1
@@ -93,10 +93,10 @@ sqlite3, migrations
 Steps:
 {"Name":"Detect New Migration Files","Text":"Found 1 new migration files (from 2 total)"}
 {"Name":"Replay Migration Files","Text":"Loaded 1 changes on dev database"}
-{"Name":"Analyze 2.sql","Text":"1 reports were found in analysis","Result":{"Name":"2.sql","Text":"CREATE TABLE pets (id INT)\nDROP TABLE users","Reports":[{"Text":"Report 2","Diagnostics":[{"Pos":1,"Text":"Diagnostic 1","Code":""},{"Pos":2,"Text":"Diagnostic 2","Code":""}]}]}}
+{"Name":"Analyze 2.sql","Text":"1 reports were found in analysis","Result":{"Name":"2.sql","Text":"CREATE TABLE pets (id INT);\nDROP TABLE users;","Reports":[{"Text":"Report 2","Diagnostics":[{"Pos":1,"Text":"Diagnostic 1","Code":""},{"Pos":2,"Text":"Diagnostic 2","Code":""}]}]}}
 
 Files:
-{"Name":"2.sql","Text":"CREATE TABLE pets (id INT)\nDROP TABLE users","Reports":[{"Text":"Report 2","Diagnostics":[{"Pos":1,"Text":"Diagnostic 1","Code":""},{"Pos":2,"Text":"Diagnostic 2","Code":""}]}]}
+{"Name":"2.sql","Text":"CREATE TABLE pets (id INT);\nDROP TABLE users;","Reports":[{"Text":"Report 2","Diagnostics":[{"Pos":1,"Text":"Diagnostic 1","Code":""},{"Pos":2,"Text":"Diagnostic 2","Code":""}]}]}
 
 
 Current Schema:
diff --git a/internal/integration/testdata/postgres/cli-migrate-diff-policy.txt b/internal/integration/testdata/postgres/cli-migrate-diff-policy.txt
new file mode 100644
index 00000000..52db0010
--- /dev/null
+++ b/internal/integration/testdata/postgres/cli-migrate-diff-policy.txt
@@ -0,0 +1,50 @@
+only postgres15
+
+atlas migrate --env dev diff --dev-url URL --to file://./1.hcl first
+cmpmig 0 1.sql
+
+atlas migrate --env dev diff --dev-url URL --to file://./2.hcl second
+cmpmig 1 2.sql
+
+-- atlas.hcl --
+env "dev" {
+  diff {
+    concurrent_index {
+      add  = true
+      drop = true
+    }
+  }
+}
+
+-- 1.hcl --
+schema "script_cli_migrate_diff_policy" {}
+
+table "users" {
+  schema = schema.script_cli_migrate_diff_policy
+  column "id" {
+    null = false
+    type = bigint
+  }
+}
+
+-- 1.sql --
+-- Create "users" table
+CREATE TABLE "users" ("id" bigint NOT NULL);
+
+-- 2.hcl --
+schema "script_cli_migrate_diff_policy" {}
+
+table "users" {
+  schema = schema.script_cli_migrate_diff_policy
+  column "id" {
+    null = false
+    type = bigint
+  }
+  index "users_idx" {
+    columns = [column.id]
+  }
+}
+
+-- 2.sql --
+-- Create index "users_idx" to table: "users"
+CREATE INDEX CONCURRENTLY "users_idx" ON "users" ("id");
\ No newline at end of file
diff --git a/internal/integration/testdata/postgres/cli-migrate-diff.txt b/internal/integration/testdata/postgres/cli-migrate-diff.txt
index 4ce49483..31092027 100644
--- a/internal/integration/testdata/postgres/cli-migrate-diff.txt
+++ b/internal/integration/testdata/postgres/cli-migrate-diff.txt
@@ -20,7 +20,6 @@ table "users" {
   column "id" {
     null = false
     type = bigint
-    auto_increment = true
   }
   primary_key  {
     columns = [column.id]
@@ -39,7 +38,6 @@ table "users" {
   column "id" {
     null = false
     type = bigint
-    auto_increment = true
   }
   column "create_time" {
     null    = false
diff --git a/sql/mysql/diff_test.go b/sql/mysql/diff_test.go
index b98b6a0c..f6b3714e 100644
--- a/sql/mysql/diff_test.go
+++ b/sql/mysql/diff_test.go
@@ -803,6 +803,5 @@ func TestSkipChanges(t *testing.T) {
 		require.Len(t, changes, 1)
 		require.Len(t, changes[0].(*schema.ModifyTable).Changes, 1)
 		require.IsType(t, &schema.DropColumn{}, changes[0].(*schema.ModifyTable).Changes[0])
-
 	})
 }
diff --git a/sql/postgres/diff_test.go b/sql/postgres/diff_test.go
index dd320b54..13200e8d 100644
--- a/sql/postgres/diff_test.go
+++ b/sql/postgres/diff_test.go
@@ -5,12 +5,13 @@
 package postgres
 
 import (
+	"context"
 	"testing"
 
-	"github.com/DATA-DOG/go-sqlmock"
-
+	"ariga.io/atlas/schemahcl"
 	"ariga.io/atlas/sql/schema"
 
+	"github.com/DATA-DOG/go-sqlmock"
 	"github.com/stretchr/testify/require"
 )
 
@@ -536,3 +537,29 @@ func TestDefaultDiff(t *testing.T) {
 	require.Len(t, changes, 1)
 	require.IsType(t, &schema.DropTable{}, changes[0])
 }
+
+func TestDiff_AnnotateChanges(t *testing.T) {
+	var cfg struct {
+		schemahcl.DefaultExtension
+	}
+	// language=hcl
+	err := schemahcl.New().EvalBytes([]byte(`
+concurrent_index {
+  add  = true
+  drop = true
+}
+`), &cfg, nil)
+	require.NoError(t, err)
+	from := schema.New("public").AddTables(schema.NewTable("users").AddIndexes(schema.NewIndex("users_pkey_old").AddColumns(schema.NewIntColumn("id", "int"))))
+	to := schema.New("public").AddTables(schema.NewTable("users").AddIndexes(schema.NewIndex("users_pkey_new").AddColumns(schema.NewIntColumn("id", "int"))))
+	changes, err := DefaultDiff.SchemaDiff(from, to, func(opts *schema.DiffOptions) { opts.Extra = cfg.DefaultExtension })
+	require.NoError(t, err)
+	require.Len(t, changes, 1)
+	plan, err := DefaultPlan.PlanChanges(context.Background(), "changes", changes)
+	require.NoError(t, err)
+	require.Len(t, plan.Changes, 2)
+	require.Equal(t, `DROP INDEX CONCURRENTLY "public"."users_pkey_old"`, plan.Changes[0].Cmd)
+	require.Equal(t, `CREATE INDEX CONCURRENTLY "users_pkey_old" ON "public"."users" ("id")`, plan.Changes[0].Reverse)
+	require.Equal(t, `CREATE INDEX CONCURRENTLY "users_pkey_new" ON "public"."users" ("id")`, plan.Changes[1].Cmd)
+	require.Equal(t, `DROP INDEX CONCURRENTLY "public"."users_pkey_new"`, plan.Changes[1].Reverse)
+}