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