mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-12 10:32:27 -06:00
Merge pull request #5583 from dolthub/zachmu/diff-schema-fixes
Bug fix for view and trigger diffs in SQL and JSON diff outputs
This commit is contained in:
@@ -22,7 +22,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
textdiff "github.com/andreyvit/diff"
|
||||
"github.com/dolthub/go-mysql-server/sql"
|
||||
"github.com/dolthub/go-mysql-server/sql/types"
|
||||
|
||||
@@ -43,7 +42,6 @@ import (
|
||||
|
||||
type diffOutput int
|
||||
type diffPart int
|
||||
type diffMode int
|
||||
|
||||
const (
|
||||
SchemaOnlyDiff diffPart = 1 // 0b0001
|
||||
@@ -63,7 +61,6 @@ const (
|
||||
SummaryFlag = "summary"
|
||||
whereParam = "where"
|
||||
limitParam = "limit"
|
||||
SQLFlag = "sql"
|
||||
SkinnyFlag = "skinny"
|
||||
MergeBase = "merge-base"
|
||||
DiffMode = "diff-mode"
|
||||
@@ -526,21 +523,27 @@ func diffUserTables(ctx context.Context, dEnv *env.DoltEnv, dArgs *diffArgs) err
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
|
||||
doltSchemasChanged := false
|
||||
for _, td := range tableDeltas {
|
||||
if !dArgs.tableSet.Contains(td.FromName) && !dArgs.tableSet.Contains(td.ToName) {
|
||||
if !shouldPrintTableDelta(dArgs.tableSet, td) {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(td.ToName) != doltdb.SchemasTableName {
|
||||
|
||||
if isDoltSchemasTable(td) {
|
||||
// save dolt_schemas table diff for last in diff output
|
||||
doltSchemasChanged = true
|
||||
} else {
|
||||
verr := diffUserTable(sqlCtx, td, sqlEng, dArgs, dw)
|
||||
if verr != nil {
|
||||
return verr
|
||||
}
|
||||
} else {
|
||||
// dolt_schemas table is treated as a special case. diff the rows of the table, and print fragments as DDL
|
||||
verr := diffDoltSchemasTable(sqlCtx, td, sqlEng, dArgs, dw)
|
||||
if verr != nil {
|
||||
return verr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if doltSchemasChanged {
|
||||
verr := diffDoltSchemasTable(sqlCtx, sqlEng, dArgs, dw)
|
||||
if verr != nil {
|
||||
return verr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,6 +555,15 @@ func diffUserTables(ctx context.Context, dEnv *env.DoltEnv, dArgs *diffArgs) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldPrintTableDelta(tablesToPrint *set.StrSet, td diff.TableDelta) bool {
|
||||
// TODO: this should be case insensitive
|
||||
return tablesToPrint.Contains(td.FromName) || tablesToPrint.Contains(td.ToName)
|
||||
}
|
||||
|
||||
func isDoltSchemasTable(td diff.TableDelta) bool {
|
||||
return td.FromName == doltdb.SchemasTableName || td.ToName == doltdb.SchemasTableName
|
||||
}
|
||||
|
||||
func diffUserTable(
|
||||
ctx *sql.Context,
|
||||
td diff.TableDelta,
|
||||
@@ -581,7 +593,7 @@ func diffUserTable(
|
||||
}
|
||||
|
||||
if dArgs.diffParts&SchemaOnlyDiff != 0 {
|
||||
err := dw.WriteSchemaDiff(ctx, dArgs.toRoot, td)
|
||||
err := dw.WriteTableSchemaDiff(ctx, dArgs.toRoot, td)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
@@ -603,17 +615,14 @@ func diffUserTable(
|
||||
|
||||
func diffDoltSchemasTable(
|
||||
sqlCtx *sql.Context,
|
||||
td diff.TableDelta,
|
||||
sqlEng *engine.SqlEngine,
|
||||
dArgs *diffArgs,
|
||||
dw diffWriter,
|
||||
) errhand.VerboseError {
|
||||
err := dw.BeginTable(sqlCtx, td)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("select from_fragment,to_fragment from dolt_diff('%s','%s','%s')", dArgs.fromRef, dArgs.toRef, doltdb.SchemasTableName)
|
||||
query := fmt.Sprintf("select from_name,to_name,from_type,to_type,from_fragment,to_fragment "+
|
||||
"from dolt_diff('%s','%s','%s') "+
|
||||
"order by coalesce(from_type, to_type), coalesce(from_name, to_name)",
|
||||
dArgs.fromRef, dArgs.toRef, doltdb.SchemasTableName)
|
||||
|
||||
_, rowIter, err := sqlEng.Query(sqlCtx, query)
|
||||
if err != nil {
|
||||
@@ -629,30 +638,52 @@ func diffDoltSchemasTable(
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
|
||||
from := ""
|
||||
var fragmentName string
|
||||
if row[0] != nil {
|
||||
from = fmt.Sprintf("%v;", row[0])
|
||||
fragmentName = row[0].(string)
|
||||
} else {
|
||||
fragmentName = row[1].(string)
|
||||
}
|
||||
to := ""
|
||||
if row[1] != nil {
|
||||
to = fmt.Sprintf("%v;", row[1])
|
||||
|
||||
var fragmentType string
|
||||
if row[2] != nil {
|
||||
fragmentType = row[2].(string)
|
||||
} else {
|
||||
fragmentType = row[3].(string)
|
||||
}
|
||||
if from != to {
|
||||
cli.Println(textdiff.LineDiff(from, to))
|
||||
|
||||
var oldFragment string
|
||||
var newFragment string
|
||||
if row[4] != nil {
|
||||
oldFragment = row[4].(string)
|
||||
// Typically schema fragements have the semicolons stripped, so put it back on
|
||||
if len(oldFragment) > 0 && oldFragment[len(oldFragment)-1] != ';' {
|
||||
oldFragment += ";"
|
||||
}
|
||||
}
|
||||
if row[5] != nil {
|
||||
newFragment = row[5].(string)
|
||||
// Typically schema fragements have the semicolons stripped, so put it back on
|
||||
if len(newFragment) > 0 && newFragment[len(newFragment)-1] != ';' {
|
||||
newFragment += ";"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeSqlSchemaDiff(ctx context.Context, td diff.TableDelta, toSchemas map[string]schema.Schema) errhand.VerboseError {
|
||||
ddlStatements, err := diff.SqlSchemaDiff(ctx, td, toSchemas)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
|
||||
for _, stmt := range ddlStatements {
|
||||
cli.Println(stmt)
|
||||
switch fragmentType {
|
||||
case "view":
|
||||
err := dw.WriteViewDiff(sqlCtx, fragmentName, oldFragment, newFragment)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
case "trigger":
|
||||
err := dw.WriteTriggerDiff(sqlCtx, fragmentName, oldFragment, newFragment)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
cli.PrintErrf("Unrecognized schema element type: %s", fragmentType)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -16,6 +16,7 @@ package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
ejson "encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -42,8 +43,12 @@ import (
|
||||
type diffWriter interface {
|
||||
// BeginTable is called when a new table is about to be written, before any schema or row diffs are written
|
||||
BeginTable(ctx context.Context, td diff.TableDelta) error
|
||||
// WriteSchemaDiff is called to write a schema diff for the table given (if requested by args)
|
||||
WriteSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error
|
||||
// WriteTableSchemaDiff is called to write a schema diff for the table given (if requested by args)
|
||||
WriteTableSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error
|
||||
// WriteTriggerDiff is called to write a trigger diff
|
||||
WriteTriggerDiff(ctx context.Context, triggerName, oldDefn, newDefn string) error
|
||||
// WriteViewDiff is called to write a view diff
|
||||
WriteViewDiff(ctx context.Context, viewName, oldDefn, newDefn string) error
|
||||
// RowWriter returns a row writer for the table delta provided, which will have Close() called on it when rows are
|
||||
// done being written.
|
||||
RowWriter(ctx context.Context, td diff.TableDelta, unionSch sql.Schema) (diff.SqlRowDiffWriter, error)
|
||||
@@ -216,7 +221,7 @@ func (t tabularDiffWriter) BeginTable(ctx context.Context, td diff.TableDelta) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t tabularDiffWriter) WriteSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
func (t tabularDiffWriter) WriteTableSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
fromSch, toSch, err := td.GetSchemas(ctx)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("cannot retrieve schema for table %s", td.ToName).AddCause(err).Build()
|
||||
@@ -266,6 +271,17 @@ func (t tabularDiffWriter) WriteSchemaDiff(ctx context.Context, toRoot *doltdb.R
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t tabularDiffWriter) WriteTriggerDiff(ctx context.Context, triggerName, oldDefn, newDefn string) error {
|
||||
// identical implementation
|
||||
return t.WriteViewDiff(ctx, triggerName, oldDefn, newDefn)
|
||||
}
|
||||
|
||||
func (t tabularDiffWriter) WriteViewDiff(ctx context.Context, viewName, oldDefn, newDefn string) error {
|
||||
diffString := textdiff.LineDiff(oldDefn, newDefn)
|
||||
cli.Println(diffString)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t tabularDiffWriter) RowWriter(ctx context.Context, td diff.TableDelta, unionSch sql.Schema) (diff.SqlRowDiffWriter, error) {
|
||||
return tabular.NewFixedWidthDiffTableWriter(unionSch, iohelp.NopWrCloser(cli.CliOut), 100), nil
|
||||
}
|
||||
@@ -282,13 +298,50 @@ func (s sqlDiffWriter) BeginTable(ctx context.Context, td diff.TableDelta) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sqlDiffWriter) WriteSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
func (s sqlDiffWriter) WriteTableSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
toSchemas, err := toRoot.GetAllSchemas(ctx)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("could not read schemas from toRoot").AddCause(err).Build()
|
||||
}
|
||||
|
||||
return writeSqlSchemaDiff(ctx, td, toSchemas)
|
||||
ddlStatements, err := diff.SqlSchemaDiff(ctx, td, toSchemas)
|
||||
if err != nil {
|
||||
return errhand.VerboseErrorFromError(err)
|
||||
}
|
||||
|
||||
for _, stmt := range ddlStatements {
|
||||
cli.Println(stmt)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sqlDiffWriter) WriteTriggerDiff(ctx context.Context, triggerName, oldDefn, newDefn string) error {
|
||||
// definitions will already be semicolon terminated, no need to add additional ones
|
||||
if oldDefn == "" {
|
||||
cli.Println(newDefn)
|
||||
} else if newDefn == "" {
|
||||
cli.Println(fmt.Sprintf("DROP TRIGGER %s;", sql.QuoteIdentifier(triggerName)))
|
||||
} else {
|
||||
cli.Println(fmt.Sprintf("DROP TRIGGER %s;", sql.QuoteIdentifier(triggerName)))
|
||||
cli.Println(newDefn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sqlDiffWriter) WriteViewDiff(ctx context.Context, viewName, oldDefn, newDefn string) error {
|
||||
// definitions will already be semicolon terminated, no need to add additional ones
|
||||
if oldDefn == "" {
|
||||
cli.Println(newDefn)
|
||||
} else if newDefn == "" {
|
||||
cli.Println(fmt.Sprintf("DROP VIEW %s;", sql.QuoteIdentifier(viewName)))
|
||||
} else {
|
||||
cli.Println(fmt.Sprintf("DROP VIEW %s;", sql.QuoteIdentifier(viewName)))
|
||||
cli.Println(newDefn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sqlDiffWriter) RowWriter(ctx context.Context, td diff.TableDelta, unionSch sql.Schema) (diff.SqlRowDiffWriter, error) {
|
||||
@@ -301,11 +354,12 @@ func (s sqlDiffWriter) RowWriter(ctx context.Context, td diff.TableDelta, unionS
|
||||
}
|
||||
|
||||
type jsonDiffWriter struct {
|
||||
wr io.WriteCloser
|
||||
schemaDiffWriter diff.SchemaDiffWriter
|
||||
rowDiffWriter diff.SqlRowDiffWriter
|
||||
schemaDiffsWritten int
|
||||
tablesWritten int
|
||||
wr io.WriteCloser
|
||||
schemaDiffWriter diff.SchemaDiffWriter
|
||||
rowDiffWriter diff.SqlRowDiffWriter
|
||||
tablesWritten int
|
||||
triggersWritten int
|
||||
viewsWritten int
|
||||
}
|
||||
|
||||
var _ diffWriter = (*tabularDiffWriter)(nil)
|
||||
@@ -316,12 +370,27 @@ func newJsonDiffWriter(wr io.WriteCloser) (*jsonDiffWriter, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
const tablesHeader = `"tables":[`
|
||||
const jsonDiffTableHeader = `{"name":"%s","schema_diff":`
|
||||
const jsonDiffFooter = `}]}`
|
||||
const jsonDiffDataDiffHeader = `],"data_diff":[`
|
||||
const jsonDataDiffFooter = `}]`
|
||||
|
||||
func (j *jsonDiffWriter) beginDocumentIfNecessary() error {
|
||||
if j.tablesWritten == 0 && j.triggersWritten == 0 && j.viewsWritten == 0 {
|
||||
_, err := j.wr.Write([]byte("{"))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jsonDiffWriter) BeginTable(ctx context.Context, td diff.TableDelta) error {
|
||||
if j.schemaDiffWriter == nil {
|
||||
err := iohelp.WriteAll(j.wr, []byte(`{"tables":[`))
|
||||
err := j.beginDocumentIfNecessary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if j.tablesWritten == 0 {
|
||||
err := iohelp.WriteAll(j.wr, []byte(tablesHeader))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -332,7 +401,12 @@ func (j *jsonDiffWriter) BeginTable(ctx context.Context, td diff.TableDelta) err
|
||||
}
|
||||
}
|
||||
|
||||
err := iohelp.WriteAll(j.wr, []byte(fmt.Sprintf(jsonDiffTableHeader, td.ToName)))
|
||||
tableName := td.FromName
|
||||
if len(tableName) == 0 {
|
||||
tableName = td.ToName
|
||||
}
|
||||
|
||||
err = iohelp.WriteAll(j.wr, []byte(fmt.Sprintf(jsonDiffTableHeader, tableName)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -343,7 +417,7 @@ func (j *jsonDiffWriter) BeginTable(ctx context.Context, td diff.TableDelta) err
|
||||
return err
|
||||
}
|
||||
|
||||
func (j *jsonDiffWriter) WriteSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
func (j *jsonDiffWriter) WriteTableSchemaDiff(ctx context.Context, toRoot *doltdb.RootValue, td diff.TableDelta) error {
|
||||
toSchemas, err := toRoot.GetAllSchemas(ctx)
|
||||
if err != nil {
|
||||
return errhand.BuildDError("could not read schemas from toRoot").AddCause(err).Build()
|
||||
@@ -366,7 +440,7 @@ func (j *jsonDiffWriter) WriteSchemaDiff(ctx context.Context, toRoot *doltdb.Roo
|
||||
|
||||
func (j *jsonDiffWriter) RowWriter(ctx context.Context, td diff.TableDelta, unionSch sql.Schema) (diff.SqlRowDiffWriter, error) {
|
||||
// close off the schema diff block, start the data block
|
||||
err := iohelp.WriteAll(j.wr, []byte(`],"data_diff":[`))
|
||||
err := iohelp.WriteAll(j.wr, []byte(jsonDiffDataDiffHeader))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -390,9 +464,133 @@ func (j *jsonDiffWriter) RowWriter(ctx context.Context, td diff.TableDelta, unio
|
||||
return j.rowDiffWriter, err
|
||||
}
|
||||
|
||||
func (j *jsonDiffWriter) WriteTriggerDiff(ctx context.Context, triggerName, oldDefn, newDefn string) error {
|
||||
err := j.beginDocumentIfNecessary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if j.triggersWritten == 0 {
|
||||
// end the table if necessary
|
||||
if j.tablesWritten > 0 {
|
||||
_, err := j.wr.Write([]byte(jsonDataDiffFooter + ","))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
_, err := j.wr.Write([]byte(`"triggers":[`))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err := j.wr.Write([]byte(","))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
triggerNameBytes, err := ejson.Marshal(triggerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldDefnBytes, err := ejson.Marshal(oldDefn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDefnBytes, err := ejson.Marshal(newDefn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = j.wr.Write([]byte(fmt.Sprintf(`{"name":%s,"from_definition":%s,"to_definition":%s}`,
|
||||
triggerNameBytes, oldDefnBytes, newDefnBytes)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j.triggersWritten++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jsonDiffWriter) WriteViewDiff(ctx context.Context, viewName, oldDefn, newDefn string) error {
|
||||
err := j.beginDocumentIfNecessary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if j.viewsWritten == 0 {
|
||||
// end the previous block if necessary
|
||||
if j.tablesWritten > 0 && j.triggersWritten == 0 {
|
||||
_, err := j.wr.Write([]byte(jsonDataDiffFooter + ","))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if j.triggersWritten > 0 {
|
||||
_, err := j.wr.Write([]byte("],"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if j.viewsWritten == 0 {
|
||||
_, err := j.wr.Write([]byte(`"views":[`))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err := j.wr.Write([]byte(","))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
viewNameBytes, err := ejson.Marshal(viewName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldDefnBytes, err := ejson.Marshal(oldDefn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newDefnBytes, err := ejson.Marshal(newDefn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = j.wr.Write([]byte(fmt.Sprintf(`{"name":%s,"from_definition":%s,"to_definition":%s}`,
|
||||
viewNameBytes, oldDefnBytes, newDefnBytes)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
j.viewsWritten++
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jsonDiffWriter) Close(ctx context.Context) error {
|
||||
if j.tablesWritten > 0 {
|
||||
err := iohelp.WriteLine(j.wr, jsonDiffFooter)
|
||||
if j.tablesWritten > 0 || j.triggersWritten > 0 || j.viewsWritten > 0 {
|
||||
// We only need to close off the "tables" array if we didn't also write a view / trigger
|
||||
// (which also closes that array)
|
||||
if j.triggersWritten == 0 && j.viewsWritten == 0 {
|
||||
_, err := j.wr.Write([]byte(jsonDataDiffFooter))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// if we did write a trigger or view, we need to close off that array
|
||||
_, err := j.wr.Write([]byte("]"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := iohelp.WriteLine(j.wr, "}")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -159,6 +159,14 @@ func GetTableDeltas(ctx context.Context, fromRoot, toRoot *doltdb.RootValue) (de
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Make sure we always return the same order of deltas
|
||||
sort.Slice(deltas, func(i, j int) bool {
|
||||
if deltas[i].FromName == deltas[j].FromName {
|
||||
return deltas[i].ToName < deltas[j].ToName
|
||||
}
|
||||
return deltas[i].FromName < deltas[j].FromName
|
||||
})
|
||||
|
||||
return deltas, nil
|
||||
}
|
||||
|
||||
@@ -552,7 +560,6 @@ func fkSlicesAreEqual(from, to []doltdb.ForeignKey) bool {
|
||||
|
||||
// SqlSchemaDiff returns a slice of DDL statements that will transform the schema in the from delta to the schema in
|
||||
// the to delta.
|
||||
// TODO: this doesn't handle constraints or triggers
|
||||
func SqlSchemaDiff(ctx context.Context, td TableDelta, toSchemas map[string]schema.Schema) ([]string, error) {
|
||||
fromSch, toSch, err := td.GetSchemas(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -93,11 +93,13 @@ SQL
|
||||
|
||||
run dolt ls --all
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "dolt_schemas" ]]
|
||||
[[ "$output" =~ "dolt_schemas" ]] || false
|
||||
|
||||
dolt diff
|
||||
run dolt diff
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "dolt_schemas" ]]
|
||||
[[ "$output" =~ "-create view four as select 2+2 as res from dual" ]] || false
|
||||
[[ ! "$output" =~ "dolt_schemas" ]] || false
|
||||
|
||||
dolt commit -Am "dropped a view"
|
||||
dolt sql -q "drop view six"
|
||||
@@ -105,11 +107,12 @@ SQL
|
||||
# Dropping all views should result in the dolt_schemas table deleting itself
|
||||
run dolt ls --all
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" =~ "dolt_schemas" ]]
|
||||
[[ ! "$output" =~ "dolt_schemas" ]] || false
|
||||
|
||||
run dolt diff
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "deleted table" ]]
|
||||
[[ "$output" =~ "-create view six as select 3+3 as res from dual" ]] || false
|
||||
[[ ! "$output" =~ "deleted table" ]] || false
|
||||
|
||||
dolt commit -Am "no views left"
|
||||
|
||||
|
||||
1
integration-tests/bats/diff.json
Normal file
1
integration-tests/bats/diff.json
Normal file
@@ -0,0 +1 @@
|
||||
{"tables":[{"name":"test","schema_diff":[],"data_diff":[{"from_row":{"c1":5,"c2":6,"pk":4},"to_row":{}},{"from_row":{},"to_row":{"c1":8,"c2":9,"pk":7}}]}],"triggers":[{"name":"tr1","from_definition":"","to_definition":"create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;"}],"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select \"hello\" from test;"}]}
|
||||
@@ -120,6 +120,161 @@ EOF
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
}
|
||||
|
||||
@test "json-diff: views" {
|
||||
dolt sql <<SQL
|
||||
drop table test;
|
||||
create table test (pk int primary key, c1 int, c2 int);
|
||||
call dolt_add('.');
|
||||
insert into test values (1,2,3);
|
||||
insert into test values (4,5,6);
|
||||
SQL
|
||||
dolt commit -am "First commit"
|
||||
|
||||
dolt sql <<SQL
|
||||
create view v1 as select * from test;
|
||||
SQL
|
||||
dolt commit -Am "Second commit"
|
||||
|
||||
dolt diff -r json HEAD HEAD~
|
||||
run dolt diff -r json HEAD HEAD~
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"views":[{"name":"v1","from_definition":"create view v1 as select * from test;","to_definition":""}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
dolt diff -r json HEAD~ HEAD
|
||||
run dolt diff -r json HEAD~ HEAD
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select * from test;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
dolt sql <<SQL
|
||||
drop view v1;
|
||||
create view v1 as select "one" from dual;
|
||||
SQL
|
||||
|
||||
dolt commit -Am "redefined view"
|
||||
|
||||
dolt diff -r json HEAD~ HEAD
|
||||
run dolt diff -r json HEAD~ HEAD
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"views":[{"name":"v1","from_definition":"create view v1 as select * from test;","to_definition":"create view v1 as select \"one\" from dual;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
}
|
||||
|
||||
@test "json-diff: views, triggers, tables" {
|
||||
dolt sql <<SQL
|
||||
drop table test;
|
||||
create table test (pk int primary key, c1 int, c2 int);
|
||||
call dolt_add('.');
|
||||
insert into test values (1,2,3);
|
||||
insert into test values (4,5,6);
|
||||
SQL
|
||||
dolt commit -am "Table with rows"
|
||||
|
||||
dolt sql <<SQL
|
||||
insert into test values (7,8,9);
|
||||
delete from test where pk = 4;
|
||||
SQL
|
||||
dolt commit -Am "Table data diff"
|
||||
|
||||
dolt sql <<SQL
|
||||
create view v1 as select "hello" from test;
|
||||
SQL
|
||||
dolt commit -Am "View"
|
||||
|
||||
dolt sql <<SQL
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;
|
||||
SQL
|
||||
dolt commit -Am "Trigger"
|
||||
|
||||
# Only table data diff
|
||||
dolt diff -r json HEAD~3 HEAD~2
|
||||
run dolt diff -r json HEAD~3 HEAD~2
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"tables":[{"name":"test","schema_diff":[],"data_diff":[{"from_row":{"c1":5,"c2":6,"pk":4},"to_row":{}},{"from_row":{},"to_row":{"c1":8,"c2":9,"pk":7}}]}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
# Only view diff
|
||||
dolt diff -r json HEAD~2 HEAD~
|
||||
run dolt diff -r json HEAD~2 HEAD~
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select \"hello\" from test;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
# Only trigger diff
|
||||
dolt diff -r json HEAD~ HEAD
|
||||
run dolt diff -r json HEAD~ HEAD
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"triggers":[{"name":"tr1","from_definition":"","to_definition":"create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
# View and trigger diff
|
||||
dolt diff -r json HEAD~2 HEAD
|
||||
run dolt diff -r json HEAD~2 HEAD
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"triggers":[{"name":"tr1","from_definition":"","to_definition":"create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;"}],"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select \"hello\" from test;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
# Table and view diff
|
||||
dolt diff -r json HEAD~3 HEAD~
|
||||
run dolt diff -r json HEAD~3 HEAD~
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"tables":[{"name":"test","schema_diff":[],"data_diff":[{"from_row":{"c1":5,"c2":6,"pk":4},"to_row":{}},{"from_row":{},"to_row":{"c1":8,"c2":9,"pk":7}}]}],"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select \"hello\" from test;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
|
||||
# All three kinds of diff
|
||||
dolt diff -r json HEAD~3 HEAD
|
||||
run dolt diff -r json HEAD~3 HEAD
|
||||
|
||||
EXPECTED=$(cat <<'EOF'
|
||||
{"tables":[{"name":"test","schema_diff":[],"data_diff":[{"from_row":{"c1":5,"c2":6,"pk":4},"to_row":{}},{"from_row":{},"to_row":{"c1":8,"c2":9,"pk":7}}]}],"triggers":[{"name":"tr1","from_definition":"","to_definition":"create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;"}],"views":[{"name":"v1","from_definition":"","to_definition":"create view v1 as select \"hello\" from test;"}]}
|
||||
EOF
|
||||
)
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$EXPECTED" ]] || false
|
||||
}
|
||||
|
||||
@test "json-diff: with table args" {
|
||||
dolt sql -q 'create table other (pk int not null primary key)'
|
||||
dolt add .
|
||||
|
||||
@@ -713,3 +713,154 @@ SQL
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ 'INSERT INTO `test` (`pk`,`c1`) VALUES (0,NULL)' ]] || false
|
||||
}
|
||||
|
||||
@test "sql-diff: views, triggers, tables" {
|
||||
dolt sql <<SQL
|
||||
create table test (pk int primary key, c1 int, c2 int);
|
||||
call dolt_add('.');
|
||||
insert into test values (1,2,3);
|
||||
insert into test values (4,5,6);
|
||||
SQL
|
||||
dolt commit -am "Table with rows"
|
||||
|
||||
dolt sql <<SQL
|
||||
insert into test values (7,8,9);
|
||||
delete from test where pk = 4;
|
||||
SQL
|
||||
dolt commit -Am "Table data diff"
|
||||
|
||||
dolt sql <<SQL
|
||||
create view v1 as select "hello" from test;
|
||||
SQL
|
||||
dolt commit -Am "View"
|
||||
|
||||
dolt sql <<SQL
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;
|
||||
SQL
|
||||
dolt commit -Am "Trigger"
|
||||
|
||||
# Only table data diff
|
||||
dolt diff -r sql HEAD~3 HEAD~2
|
||||
run dolt diff -r sql HEAD~3 HEAD~2
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
DELETE FROM `test` WHERE `pk`=4;
|
||||
INSERT INTO `test` (`pk`,`c1`,`c2`) VALUES (7,8,9);
|
||||
EOF
|
||||
|
||||
# We can't do direct bash comparisons because of newlines, so use diff to compare
|
||||
# Diff returns non-zero unless empty
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
diff -w expected actual
|
||||
|
||||
# Only view diff
|
||||
dolt diff -r sql HEAD~2 HEAD~
|
||||
run dolt diff -r sql HEAD~2 HEAD~
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
create view v1 as select "hello" from test;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
|
||||
# Only trigger diff
|
||||
dolt diff -r sql HEAD~ HEAD
|
||||
run dolt diff -r sql HEAD~ HEAD
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
|
||||
# View and trigger diff
|
||||
dolt diff -r sql HEAD~2 HEAD
|
||||
run dolt diff -r sql HEAD~2 HEAD
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<EOF
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;
|
||||
create view v1 as select "hello" from test;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
|
||||
# Table and view diff
|
||||
dolt diff -r sql HEAD~3 HEAD~
|
||||
run dolt diff -r sql HEAD~3 HEAD~
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
DELETE FROM `test` WHERE `pk`=4;
|
||||
INSERT INTO `test` (`pk`,`c1`,`c2`) VALUES (7,8,9);
|
||||
create view v1 as select "hello" from test;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
|
||||
# All three kinds of diff
|
||||
dolt diff -r sql HEAD~3 HEAD
|
||||
run dolt diff -r sql HEAD~3 HEAD
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
DELETE FROM `test` WHERE `pk`=4;
|
||||
INSERT INTO `test` (`pk`,`c1`,`c2`) VALUES (7,8,9);
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 1;
|
||||
create view v1 as select "hello" from test;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
|
||||
# check alterations of triggers and views
|
||||
dolt sql <<SQL
|
||||
drop trigger tr1;
|
||||
drop view v1;
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 100;
|
||||
create view v1 as select "goodbye" from test;
|
||||
SQL
|
||||
|
||||
dolt commit -am "new view and trigger defs"
|
||||
|
||||
dolt diff -r sql HEAD~ HEAD
|
||||
run dolt diff -r sql HEAD~ HEAD
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
cat > expected <<'EOF'
|
||||
DROP TRIGGER `tr1`;
|
||||
create trigger tr1 before insert on test for each row set new.c1 = new.c1 + 100;
|
||||
DROP VIEW `v1`;
|
||||
create view v1 as select "goodbye" from test;
|
||||
EOF
|
||||
|
||||
cat > actual <<EOF
|
||||
${output}
|
||||
EOF
|
||||
|
||||
diff -w expected actual
|
||||
}
|
||||
|
||||
@@ -68,6 +68,20 @@ export const diffTests = [
|
||||
q: "SELECT * FROM dolt_diff_stat(:fromRefName, :toRefName)",
|
||||
p: { fromRefName: "HEAD", toRefName: "WORKING" },
|
||||
res: [
|
||||
{
|
||||
table_name: "dolt_schemas",
|
||||
rows_unmodified: 0,
|
||||
rows_added: 1,
|
||||
rows_deleted: 0,
|
||||
rows_modified: 0,
|
||||
cells_added: 4,
|
||||
cells_deleted: 0,
|
||||
cells_modified: 0,
|
||||
old_row_count: 0,
|
||||
new_row_count: 1,
|
||||
old_cell_count: 0,
|
||||
new_cell_count: 4,
|
||||
},
|
||||
{
|
||||
table_name: "test",
|
||||
rows_unmodified: 2,
|
||||
@@ -96,20 +110,6 @@ export const diffTests = [
|
||||
old_cell_count: 3,
|
||||
new_cell_count: 0,
|
||||
},
|
||||
{
|
||||
table_name: "dolt_schemas",
|
||||
rows_unmodified: 0,
|
||||
rows_added: 1,
|
||||
rows_deleted: 0,
|
||||
rows_modified: 0,
|
||||
cells_added: 4,
|
||||
cells_deleted: 0,
|
||||
cells_modified: 0,
|
||||
old_row_count: 0,
|
||||
new_row_count: 1,
|
||||
old_cell_count: 0,
|
||||
new_cell_count: 4,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -306,6 +306,20 @@ export const diffTests = [
|
||||
q: "SELECT * FROM dolt_diff_stat(:refRange)",
|
||||
p: { refRange: "main...HEAD" },
|
||||
res: [
|
||||
{
|
||||
table_name: "dolt_schemas",
|
||||
rows_unmodified: 0,
|
||||
rows_added: 1,
|
||||
rows_deleted: 0,
|
||||
rows_modified: 0,
|
||||
cells_added: 4,
|
||||
cells_deleted: 0,
|
||||
cells_modified: 0,
|
||||
old_row_count: 0,
|
||||
new_row_count: 1,
|
||||
old_cell_count: 0,
|
||||
new_cell_count: 4,
|
||||
},
|
||||
{
|
||||
table_name: "test",
|
||||
rows_unmodified: 2,
|
||||
@@ -334,20 +348,6 @@ export const diffTests = [
|
||||
old_cell_count: 3,
|
||||
new_cell_count: 0,
|
||||
},
|
||||
{
|
||||
table_name: "dolt_schemas",
|
||||
rows_unmodified: 0,
|
||||
rows_added: 1,
|
||||
rows_deleted: 0,
|
||||
rows_modified: 0,
|
||||
cells_added: 4,
|
||||
cells_deleted: 0,
|
||||
cells_modified: 0,
|
||||
old_row_count: 0,
|
||||
new_row_count: 1,
|
||||
old_cell_count: 0,
|
||||
new_cell_count: 4,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user