package json import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zitadel/zitadel/backend/v3/storage/database" ) func TestFieldChange(t *testing.T) { for _, test := range []struct { name string change database.Change output string }{ { name: "single json update", change: func() database.Change { col := database.NewColumn("table", "column") change := NewFieldChange([]string{"path"}, "value") changes := NewJsonChanges(col, change) return changes }(), output: `column = jsonb_set_lax(table.column, $1, $2, true, 'delete_key')`, }, { name: "two json update", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewFieldChange([]string{"path"}, "value") change2 := NewFieldChange([]string{"path"}, "value") changes := NewJsonChanges(col, change1, change2) return changes }(), output: `column = jsonb_set_lax(jsonb_set_lax(table.column, $1, $2, true, 'delete_key'), $3, $4, true, 'delete_key')`, }, } { t.Run(test.name, func(t *testing.T) { builder := database.StatementBuilder{} err := test.change.Write(&builder) require.NoError(t, err) assert.Equal(t, test.output, builder.String()) }) } } func TestArrayChange(t *testing.T) { for _, test := range []struct { name string change database.Change output string }{ { name: "one json array add", change: func() database.Change { col := database.NewColumn("table", "column") change := NewArrayChange([]string{"path"}, "value", false) changes := NewJsonChanges(col, change) return changes }(), output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT)`, }, { name: "two json array add", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", false) change2 := NewArrayChange([]string{"path"}, "value", false) changes := NewJsonChanges(col, change1, change2) return changes }(), output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`, }, { name: "one json array remove", change: func() database.Change { col := database.NewColumn("table", "column") change := NewArrayChange([]string{"path"}, "value", true) changes := NewJsonChanges(col, change) return changes }(), output: `column = zitadel.jsonb_array_remove(table.column, $1, $2::TEXT)`, }, { name: "two json array remove", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", true) change2 := NewArrayChange([]string{"path"}, "value", true) changes := NewJsonChanges(col, change1, change2) return changes }(), output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT)`, }, } { t.Run(test.name, func(t *testing.T) { builder := database.StatementBuilder{} err := test.change.Write(&builder) require.NoError(t, err) assert.Equal(t, test.output, builder.String()) }) } } func TestArrayMixedChange(t *testing.T) { for _, test := range []struct { name string change database.Change output string }{ { name: "one json array add, one json remove", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", false) change2 := NewArrayChange([]string{"path"}, "value", true) changes := NewJsonChanges(col, change1, change2) return changes }(), output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT)`, }, { name: "one json array remove, one json array add", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", true) change2 := NewArrayChange([]string{"path"}, "value", false) changes := NewJsonChanges(col, change1, change2) return changes }(), output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT)`, }, { name: "one json array add, one json array remove, one array add", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", false) change2 := NewArrayChange([]string{"path"}, "value", true) change3 := NewArrayChange([]string{"path)"}, "value", false) changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT), $9, $10::TEXT)`, }, { name: "one json array remove, one json array add, one array remove", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", true) change2 := NewArrayChange([]string{"path"}, "value", false) change3 := NewArrayChange([]string{"path)"}, "value", true) changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`, }, } { t.Run(test.name, func(t *testing.T) { builder := database.StatementBuilder{} err := test.change.Write(&builder) require.NoError(t, err) assert.Equal(t, test.output, builder.String()) }) } } // TODO func TestFieldArrayMixedChange(t *testing.T) { for _, test := range []struct { name string change database.Change output string }{ { name: "one field change, one json array add, one json remove", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewFieldChange([]string{"path"}, "value") change2 := NewArrayChange([]string{"path)"}, "value", false) change3 := NewArrayChange([]string{"path"}, "value", true) changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = zitadel.jsonb_array_remove(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(jsonb_set_lax(table.column, $1, $2, true, 'delete_key'), $3, $4::TEXT), $5, $6::TEXT), $7, $8::TEXT)`, }, { name: "one json array add, one field change, one json remove", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path)"}, "value", false) change2 := NewFieldChange([]string{"path"}, "value") change3 := NewArrayChange([]string{"path"}, "value", true) changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = zitadel.jsonb_array_remove(jsonb_set_lax(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6, true, 'delete_key'), $7, $8::TEXT)`, }, { name: "one json remove, one json array, add one field change", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path"}, "value", true) change2 := NewArrayChange([]string{"path)"}, "value", false) change3 := NewFieldChange([]string{"path"}, "value") changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = jsonb_set_lax(zitadel.jsonb_array_append(zitadel.jsonb_array_remove(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4::TEXT), $5, $6::TEXT), $7, $8, true, 'delete_key')`, }, { name: "one json remove, one field change, one json array add", change: func() database.Change { col := database.NewColumn("table", "column") change1 := NewArrayChange([]string{"path"}, "value", true) change2 := NewFieldChange([]string{"path"}, "value") change3 := NewArrayChange([]string{"path)"}, "value", false) changes := NewJsonChanges(col, change1, change2, change3) return changes }(), output: `column = zitadel.jsonb_array_append(zitadel.jsonb_array_remove(jsonb_set_lax(zitadel.jsonb_array_remove(table.column, $1, $2::TEXT), $3, $4, true, 'delete_key'), $5, $6::TEXT), $7, $8::TEXT)`, }, } { t.Run(test.name, func(t *testing.T) { builder := database.StatementBuilder{} err := test.change.Write(&builder) require.NoError(t, err) assert.Equal(t, test.output, builder.String()) }) } }