Repository: ariga/atlas
Pull request #577 (2022-02-13 16:48:25)

sql/sqlite: support for auto_increment


Patch:
diff --git a/sql/sqlite/sqlspec.go b/sql/sqlite/sqlspec.go
index 0a3fa3a2..8e364ff2 100644
--- a/sql/sqlite/sqlspec.go
+++ b/sql/sqlite/sqlspec.go
@@ -6,6 +6,7 @@ import (
 	"ariga.io/atlas/schema/schemaspec"
 	"ariga.io/atlas/schema/schemaspec/schemahcl"
 	"ariga.io/atlas/sql/internal/specutil"
+	"ariga.io/atlas/sql/internal/sqlx"
 	"ariga.io/atlas/sql/schema"
 	"ariga.io/atlas/sql/sqlspec"
 )
@@ -29,7 +30,20 @@ func convertTable(spec *sqlspec.Table, parent *schema.Schema) (*schema.Table, er
 
 // convertColumn converts a sqlspec.Column into a schema.Column.
 func convertColumn(spec *sqlspec.Column, _ *schema.Table) (*schema.Column, error) {
-	return specutil.Column(spec, convertColumnType)
+	c, err := specutil.Column(spec, convertColumnType)
+	if err != nil {
+		return nil, err
+	}
+	if attr, ok := spec.Attr("auto_increment"); ok {
+		b, err := attr.Bool()
+		if err != nil {
+			return nil, err
+		}
+		if b {
+			c.AddAttrs(&AutoIncrement{})
+		}
+	}
+	return c, nil
 }
 
 // convertColumnType converts a sqlspec.Column into a concrete SQLite schema.Type.
@@ -55,8 +69,15 @@ func tableSpec(tab *schema.Table) (*sqlspec.Table, error) {
 }
 
 // columnSpec converts from a concrete SQLite schema.Column into a sqlspec.Column.
-func columnSpec(col *schema.Column, _ *schema.Table) (*sqlspec.Column, error) {
-	return specutil.FromColumn(col, columnTypeSpec)
+func columnSpec(c *schema.Column, _ *schema.Table) (*sqlspec.Column, error) {
+	s, err := specutil.FromColumn(c, columnTypeSpec)
+	if err != nil {
+		return nil, err
+	}
+	if sqlx.Has(c.Attrs, &AutoIncrement{}) {
+		s.Extra.Attrs = append(s.Extra.Attrs, specutil.BoolAttr("auto_increment", true))
+	}
+	return s, nil
 }
 
 // columnTypeSpec converts from a concrete MySQL schema.Type into sqlspec.Column Type.


Test patch:
diff --git a/internal/integration/script_test.go b/internal/integration/script_test.go
index 7064048b..8527dbf3 100644
--- a/internal/integration/script_test.go
+++ b/internal/integration/script_test.go
@@ -113,19 +113,24 @@ func setupScript(t *testing.T, env *testscript.Env, db *sql.DB, dropCmd string)
 	return nil
 }
 
+var (
+	keyDB  *sql.DB
+	keyDrv *sqlite.Driver
+)
+
 func (t *liteTest) setupScript(env *testscript.Env) error {
-	db, err := sql.Open("sqlite3", "file:atlas?mode=memory&cache=shared&_fk=1")
+	db, err := sql.Open("sqlite3", fmt.Sprintf("file:%s?mode=memory&cache=shared&_fk=1", filepath.Base(env.WorkDir)))
 	require.NoError(t, err)
-	t.db = db
-	env.Setenv("db", "main")
 	env.Defer(func() {
 		require.NoError(t, db.Close())
 	})
-	t.Cleanup(func() {
-		require.NoError(t, db.Close())
-	})
-	t.drv, err = sqlite.Open(db)
+	drv, err := sqlite.Open(db)
 	require.NoError(t, err)
+	env.Setenv("db", "main")
+	// Attach connection and driver to the
+	// environment as tests run in parallel.
+	env.Values[keyDB] = db
+	env.Values[keyDrv] = drv
 	return nil
 }
 
@@ -189,8 +194,11 @@ func (t *pgTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {
 
 func (t *liteTest) cmdCmpShow(ts *testscript.TestScript, _ bool, args []string) {
 	cmdCmpShow(ts, args, func(_, name string) (string, error) {
-		var stmts []string
-		rows, err := t.db.Query("SELECT sql FROM sqlite_schema where tbl_name = ?", name)
+		var (
+			stmts []string
+			db    = ts.Value(keyDB).(*sql.DB)
+		)
+		rows, err := db.Query("SELECT sql FROM sqlite_schema where tbl_name = ?", name)
 		if err != nil {
 			return "", fmt.Errorf("querying schema")
 		}
@@ -258,8 +266,11 @@ func (t *pgTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {
 
 func (t *liteTest) cmdExist(ts *testscript.TestScript, neg bool, args []string) {
 	cmdExist(ts, neg, args, func(_, name string) (bool, error) {
-		var b bool
-		if err := t.db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE `type`='table' AND `name` = ?", name).Scan(&b); err != nil {
+		var (
+			b  bool
+			db = ts.Value(keyDB).(*sql.DB)
+		)
+		if err := db.QueryRow("SELECT COUNT(*) FROM sqlite_master WHERE `type`='table' AND `name` = ?", name).Scan(&b); err != nil {
 			return false, err
 		}
 		return b, nil
@@ -326,18 +337,19 @@ func (t *liteTest) cmdSynced(ts *testscript.TestScript, neg bool, args []string)
 }
 
 func (t *liteTest) cmdApply(ts *testscript.TestScript, neg bool, args []string) {
-	cmdApply(ts, neg, args, t.drv.ApplyChanges, t.hclDiff)
+	cmdApply(ts, neg, args, ts.Value(keyDrv).(*sqlite.Driver).ApplyChanges, t.hclDiff)
 }
 
 func (t *liteTest) hclDiff(ts *testscript.TestScript, name string) []schema.Change {
 	var (
 		desired schema.Schema
 		f       = ts.ReadFile(name)
+		drv     = ts.Value(keyDrv).(*sqlite.Driver)
 	)
 	ts.Check(sqlite.UnmarshalHCL([]byte(f), &desired))
-	current, err := t.drv.InspectSchema(context.Background(), desired.Name, nil)
+	current, err := drv.InspectSchema(context.Background(), desired.Name, nil)
 	ts.Check(err)
-	changes, err := t.drv.SchemaDiff(current, &desired)
+	changes, err := drv.SchemaDiff(current, &desired)
 	ts.Check(err)
 	return changes
 }
diff --git a/internal/integration/testdata/sqlite/autoincrement.txt b/internal/integration/testdata/sqlite/autoincrement.txt
new file mode 100644
index 00000000..3a616ba6
--- /dev/null
+++ b/internal/integration/testdata/sqlite/autoincrement.txt
@@ -0,0 +1,20 @@
+apply 1.hcl
+cmpshow users 1.sql
+
+-- 1.hcl --
+schema "main" {}
+
+table "users" {
+  schema = schema.main
+  column "id" {
+    null = false
+    type = integer
+    auto_increment = true
+  }
+  primary_key  {
+    columns = [column.id]
+  }
+}
+
+-- 1.sql --
+CREATE TABLE `users` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT)
\ No newline at end of file
diff --git a/sql/mysql/sqlspec_test.go b/sql/mysql/sqlspec_test.go
index 2cb9b443..90e4dc61 100644
--- a/sql/mysql/sqlspec_test.go
+++ b/sql/mysql/sqlspec_test.go
@@ -477,7 +477,7 @@ func TestMarshalSpec_AutoIncrement(t *testing.T) {
 						Name: "id",
 						Type: &schema.ColumnType{Type: &schema.IntegerType{T: "bigint"}},
 						Attrs: []schema.Attr{
-							&AutoIncrement{V: 1000},
+							&AutoIncrement{},
 						},
 					},
 				},
diff --git a/sql/sqlite/sqlspec_test.go b/sql/sqlite/sqlspec_test.go
index a581a400..045ff6ca 100644
--- a/sql/sqlite/sqlspec_test.go
+++ b/sql/sqlite/sqlspec_test.go
@@ -19,8 +19,9 @@ schema "schema" {
 }
 
 table "table" {
-	column "col" {
+	column "id" {
 		type = integer
+		auto_increment = true
 	}
 	column "age" {
 		type = integer
@@ -32,12 +33,12 @@ table "table" {
 		type = varchar(32)
 	}
 	primary_key {
-		columns = [table.table.column.col]
+		columns = [table.table.column.id]
 	}
 	index "index" {
 		unique = true
 		columns = [
-			table.table.column.col,
+			table.table.column.id,
 			table.table.column.age,
 		]
 	}
@@ -73,12 +74,15 @@ table "accounts" {
 			Schema: exp,
 			Columns: []*schema.Column{
 				{
-					Name: "col",
+					Name: "id",
 					Type: &schema.ColumnType{
 						Type: &schema.IntegerType{
 							T: "integer",
 						},
 					},
+					Attrs: []schema.Attr{
+						&AutoIncrement{},
+					},
 				},
 				{
 					Name: "age",
@@ -169,6 +173,41 @@ table "accounts" {
 	require.EqualValues(t, exp, &s)
 }
 
+func TestMarshalSpec_AutoIncrement(t *testing.T) {
+	s := &schema.Schema{
+		Name: "test",
+		Tables: []*schema.Table{
+			{
+				Name: "users",
+				Columns: []*schema.Column{
+					{
+						Name: "id",
+						Type: &schema.ColumnType{Type: &schema.IntegerType{T: "int"}},
+						Attrs: []schema.Attr{
+							&AutoIncrement{},
+						},
+					},
+				},
+			},
+		},
+	}
+	s.Tables[0].Schema = s
+	buf, err := MarshalSpec(s, hclState)
+	require.NoError(t, err)
+	const expected = `table "users" {
+  schema = schema.test
+  column "id" {
+    null           = false
+    type           = int
+    auto_increment = true
+  }
+}
+schema "test" {
+}
+`
+	require.EqualValues(t, expected, string(buf))
+}
+
 func TestTypes(t *testing.T) {
 	for _, tt := range []struct {
 		typeExpr string