This commit is contained in:
parent
e7f9934f03
commit
8245f89305
@ -24,24 +24,36 @@ func InitDB(sql_schema string) *sqlx.DB {
|
|||||||
|
|
||||||
// SchemaFromDB takes a DB connection, checks its schema metadata tables, and returns a Schema.
|
// SchemaFromDB takes a DB connection, checks its schema metadata tables, and returns a Schema.
|
||||||
func SchemaFromDB(db *sqlx.DB) Schema {
|
func SchemaFromDB(db *sqlx.DB) Schema {
|
||||||
ret := Schema{}
|
ret := Schema{Tables: map[string]Table{}, Indexes: map[string]Index{}}
|
||||||
|
|
||||||
var tables []Table
|
var tables []Table
|
||||||
err := db.Select(&tables, `select name, is_strict, is_without_rowid from tables`)
|
err := db.Select(&tables, `select name, is_strict, is_without_rowid from tables`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tbl := range tables {
|
for _, tbl := range tables {
|
||||||
tbl.TypeName = textutils.SnakeToCamel(inflection.Singular(tbl.TableName))
|
tbl.TypeName = textutils.SnakeToCamel(inflection.Singular(tbl.TableName))
|
||||||
tbl.TypeIDName = tbl.TypeName + "ID"
|
tbl.TypeIDName = tbl.TypeName + "ID"
|
||||||
tbl.VarName = strings.ToLower(string(tbl.TableName[0]))
|
tbl.VarName = strings.ToLower(string(tbl.TableName[0]))
|
||||||
|
|
||||||
err := db.Select(&tbl.Columns, `select * from columns where table_name = ?`, tbl.TableName)
|
err = db.Select(&tbl.Columns, `select * from columns where table_name = ?`, tbl.TableName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ret[tbl.TableName] = tbl
|
ret.Tables[tbl.TableName] = tbl
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexes []Index
|
||||||
|
err = db.Select(&indexes, `select index_name, table_name, is_unique from indexes`)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, idx := range indexes {
|
||||||
|
err = db.Select(&idx.Columns, `select column_name from index_columns where index_name = ? order by rank`, idx.Name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ret.Indexes[idx.Name] = idx
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ func TestParseSchema(t *testing.T) {
|
|||||||
schema := schema.SchemaFromDB(db)
|
schema := schema.SchemaFromDB(db)
|
||||||
expected_tbls := []string{"food_types", "foods", "units", "ingredients", "recipes", "iterations", "db_version"}
|
expected_tbls := []string{"food_types", "foods", "units", "ingredients", "recipes", "iterations", "db_version"}
|
||||||
for _, tbl_name := range expected_tbls {
|
for _, tbl_name := range expected_tbls {
|
||||||
_, is_ok := schema[tbl_name]
|
_, is_ok := schema.Tables[tbl_name]
|
||||||
assert.True(is_ok)
|
assert.True(is_ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
foods := schema["foods"]
|
foods := schema.Tables["foods"]
|
||||||
assert.Equal(foods.TableName, "foods")
|
assert.Equal(foods.TableName, "foods")
|
||||||
assert.Equal(foods.TypeName, "Food")
|
assert.Equal(foods.TypeName, "Food")
|
||||||
assert.Equal(foods.TypeIDName, "FoodID")
|
assert.Equal(foods.TypeIDName, "FoodID")
|
||||||
@ -44,11 +44,36 @@ func TestParseSchema(t *testing.T) {
|
|||||||
assert.Equal(foods.Columns[16].HasDefaultValue, true)
|
assert.Equal(foods.Columns[16].HasDefaultValue, true)
|
||||||
assert.Equal(foods.Columns[16].DefaultValue, "100")
|
assert.Equal(foods.Columns[16].DefaultValue, "100")
|
||||||
|
|
||||||
ingredients := schema["ingredients"]
|
ingredients := schema.Tables["ingredients"]
|
||||||
assert.Equal(ingredients.Columns[0].Name, "rowid")
|
assert.Equal(ingredients.Columns[0].Name, "rowid")
|
||||||
assert.Equal(ingredients.Columns[0].IsPrimaryKey, true)
|
assert.Equal(ingredients.Columns[0].IsPrimaryKey, true)
|
||||||
assert.Equal(ingredients.Columns[1].Name, "food_id")
|
assert.Equal(ingredients.Columns[1].Name, "food_id")
|
||||||
assert.Equal(ingredients.Columns[1].IsForeignKey, true)
|
assert.Equal(ingredients.Columns[1].IsForeignKey, true)
|
||||||
assert.Equal(ingredients.Columns[1].ForeignKeyTargetTable, "foods")
|
assert.Equal(ingredients.Columns[1].ForeignKeyTargetTable, "foods")
|
||||||
assert.Equal(ingredients.Columns[1].ForeignKeyTargetColumn, "rowid")
|
assert.Equal(ingredients.Columns[1].ForeignKeyTargetColumn, "rowid")
|
||||||
|
|
||||||
|
// -------
|
||||||
|
// Indexes
|
||||||
|
// -------
|
||||||
|
|
||||||
|
// Unique index
|
||||||
|
units_name_idx, isOk := schema.Indexes["sqlite_autoindex_units_1"]
|
||||||
|
require.True(t, isOk)
|
||||||
|
assert.True(units_name_idx.IsUnique)
|
||||||
|
assert.Equal("units", units_name_idx.TableName)
|
||||||
|
assert.Equal([]string{"name"}, units_name_idx.Columns)
|
||||||
|
|
||||||
|
// Non-unique, declared index
|
||||||
|
foods_protein_idx, isOk := schema.Indexes["foods_protein"]
|
||||||
|
require.True(t, isOk)
|
||||||
|
assert.False(foods_protein_idx.IsUnique)
|
||||||
|
assert.Equal("foods", foods_protein_idx.TableName)
|
||||||
|
assert.Equal([]string{"protein"}, foods_protein_idx.Columns)
|
||||||
|
|
||||||
|
// Multi-column index
|
||||||
|
ingr_seq_idx, isOk := schema.Indexes["sqlite_autoindex_ingredients_1"]
|
||||||
|
require.True(t, isOk)
|
||||||
|
assert.True(ingr_seq_idx.IsUnique)
|
||||||
|
assert.Equal("ingredients", ingr_seq_idx.TableName)
|
||||||
|
assert.Equal([]string{"in_recipe_id", "list_order"}, ingr_seq_idx.Columns)
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,15 @@ type Table struct {
|
|||||||
TypeName string
|
TypeName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema is a container for a bunch of Tables, indexed by table name.
|
type Index struct {
|
||||||
type Schema map[string]Table
|
Name string `db:"index_name"`
|
||||||
|
TableName string `db:"table_name"`
|
||||||
|
Columns []string
|
||||||
|
IsUnique bool `db:"is_unique"`
|
||||||
|
// TODO: `where ...` for partial indexes
|
||||||
|
}
|
||||||
|
|
||||||
|
type Schema struct {
|
||||||
|
Tables map[string]Table
|
||||||
|
Indexes map[string]Index
|
||||||
|
}
|
||||||
|
@ -22,3 +22,17 @@ create temporary view columns as
|
|||||||
from tables
|
from tables
|
||||||
join pragma_table_info(tables.name) as table_info
|
join pragma_table_info(tables.name) as table_info
|
||||||
left join pragma_foreign_key_list(tables.name) as fk on fk."from" = column_name;
|
left join pragma_foreign_key_list(tables.name) as fk on fk."from" = column_name;
|
||||||
|
|
||||||
|
create temporary view indexes as
|
||||||
|
select idx.name as index_name,
|
||||||
|
tables.name as table_name,
|
||||||
|
idx."unique" as is_unique
|
||||||
|
from tables
|
||||||
|
join pragma_index_list(tables.name) idx;
|
||||||
|
|
||||||
|
create temporary view index_columns as
|
||||||
|
select indexes.index_name,
|
||||||
|
idx_cols.name as column_name,
|
||||||
|
idx_cols.seqno as rank
|
||||||
|
from indexes
|
||||||
|
join pragma_index_info(indexes.index_name) as idx_cols;
|
||||||
|
@ -42,6 +42,7 @@ create table foods (rowid integer primary key,
|
|||||||
density real not null default 1,
|
density real not null default 1,
|
||||||
cook_ratio real not null default 1
|
cook_ratio real not null default 1
|
||||||
) strict;
|
) strict;
|
||||||
|
create index foods_protein on foods(protein);
|
||||||
|
|
||||||
|
|
||||||
create table units (rowid integer primary key,
|
create table units (rowid integer primary key,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user