From 9b65f51aac90d2425a540d9bedb0a956cbfd7ae7 Mon Sep 17 00:00:00 2001 From: Ariel Mashraki Date: Mon, 24 Jan 2022 23:36:36 +0200 Subject: [PATCH] sql/sqlite: inspect index sort order --- sql/sqlite/inspect.go | 36 +++++++++++++++++++++++------------- sql/sqlite/inspect_test.go | 18 +++++++++--------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sql/sqlite/inspect.go b/sql/sqlite/inspect.go index 80dc9c4dee4..9207e032a49 100644 --- a/sql/sqlite/inspect.go +++ b/sql/sqlite/inspect.go @@ -189,7 +189,7 @@ func (i *inspect) indexes(ctx context.Context, t *schema.Table) error { return fmt.Errorf("sqlite: scan %q indexes: %w", t.Name, err) } for _, idx := range t.Indexes { - if err := i.indexColumns(ctx, t, idx); err != nil { + if err := i.indexInfo(ctx, t, idx); err != nil { return err } } @@ -233,33 +233,36 @@ func (i *inspect) addIndexes(t *schema.Table, rows *sql.Rows) error { return nil } -func (i *inspect) indexColumns(ctx context.Context, t *schema.Table, idx *schema.Index) error { +func (i *inspect) indexInfo(ctx context.Context, t *schema.Table, idx *schema.Index) error { rows, err := i.QueryContext(ctx, fmt.Sprintf(indexColumnsQuery, idx.Name)) if err != nil { return fmt.Errorf("sqlite: querying %q indexes: %w", t.Name, err) } defer rows.Close() for rows.Next() { - var name sql.NullString - if err := rows.Scan(&name); err != nil { + var ( + desc sql.NullBool + name sql.NullString + ) + if err := rows.Scan(&name, &desc); err != nil { return fmt.Errorf("sqlite: scanning index names: %w", err) } + part := &schema.IndexPart{SeqNo: len(idx.Parts) + 1} switch c, ok := t.Column(name.String); { case ok: - idx.Parts = append(idx.Parts, &schema.IndexPart{ - SeqNo: len(idx.Parts) + 1, - C: c, - }) + part.C = c // NULL name indicates that the index-part is an expression and we // should extract it from the `CREATE INDEX` statement (not supported atm). case !sqlx.ValidString(name): - idx.Parts = append(idx.Parts, &schema.IndexPart{ - SeqNo: len(idx.Parts) + 1, - X: &schema.RawExpr{X: ""}, - }) + part.X = &schema.RawExpr{X: ""} default: return fmt.Errorf("sqlite: column %q was not found for index %q", name.String, idx.Name) } + if desc.Bool { + // The default sort order is "ASC". + part.Attrs = append(part.Attrs, &IndexOrder{Desc: desc.Bool}) + } + idx.Parts = append(idx.Parts, part) } return nil } @@ -441,6 +444,13 @@ type ( P string } + // IndexOrder describes the sort order of an index. + // See: https://www.sqlite.org/lang_createindex.html#descending_indexes + IndexOrder struct { + schema.Attr + Desc bool + } + // IndexOrigin describes how the index was created. // See: https://www.sqlite.org/pragma.html#pragma_index_list IndexOrigin struct { @@ -663,7 +673,7 @@ const ( // Query to list table indexes. indexesQuery = "SELECT `il`.`name`, `il`.`unique`, `il`.`origin`, `il`.`partial`, `m`.`sql` FROM pragma_index_list('%s') AS il JOIN sqlite_master AS m ON il.name = m.name" // Query to list index columns. - indexColumnsQuery = "SELECT name FROM pragma_index_info('%s') ORDER BY seqno" + indexColumnsQuery = "SELECT name, desc FROM pragma_index_xinfo('%s') WHERE key = 1 ORDER BY seqno" // Query to list table foreign-keys. fksQuery = "SELECT `id`, `from`, `to`, `table`, `on_update`, `on_delete` FROM pragma_foreign_key_list('%s') ORDER BY id, seq" ) diff --git a/sql/sqlite/inspect_test.go b/sql/sqlite/inspect_test.go index fadd14e4654..a516cf73f58 100644 --- a/sql/sqlite/inspect_test.go +++ b/sql/sqlite/inspect_test.go @@ -105,17 +105,17 @@ func TestDriver_InspectTable(t *testing.T) { `)) m.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, "c1u"))). WillReturnRows(sqltest.Rows(` - name ------- - c1 - c2 + name | desc | +-------+--------+ + c1 | 1 | + c2 | 0 | `)) m.ExpectQuery(sqltest.Escape(fmt.Sprintf(indexColumnsQuery, "c1_c2"))). WillReturnRows(sqltest.Rows(` - name ------- - c1 - nil + name | desc | +-------+--------+ + c1 | 0 | + nil | 0 | `)) m.noFKs("users") }, @@ -131,7 +131,7 @@ func TestDriver_InspectTable(t *testing.T) { Unique: true, Table: t, Parts: []*schema.IndexPart{ - {SeqNo: 1, C: columns[0]}, + {SeqNo: 1, C: columns[0], Attrs: []schema.Attr{&IndexOrder{Desc: true}}}, {SeqNo: 2, C: columns[1]}, }, Attrs: []schema.Attr{