Deletes CPA values on CPA field type change (#31122)
* Deletes CPA values on CPA field type change * Fix error method name reference * Cleans the state when a CPA field's type is updated * Fix types * Fix linter * Webapp no longer makes a decision on the change and server sents a flag in the WS message * Fix linter --------- Co-authored-by: Miguel de la Cruz <miguel@ctrlz.es>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
b3649132d0
Коммит
e51ea025db
@@ -9452,11 +9452,11 @@ func (s *RetryLayerPropertyValueStore) Delete(groupID string, id string) error {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerPropertyValueStore) DeleteForField(id string) error {
|
||||
func (s *RetryLayerPropertyValueStore) DeleteForField(groupID string, fieldID string) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.PropertyValueStore.DeleteForField(id)
|
||||
err := s.PropertyValueStore.DeleteForField(groupID, fieldID)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -327,12 +327,16 @@ func (s *SqlPropertyValueStore) Delete(groupID string, id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SqlPropertyValueStore) DeleteForField(fieldID string) error {
|
||||
func (s *SqlPropertyValueStore) DeleteForField(groupID, fieldID string) error {
|
||||
builder := s.getQueryBuilder().
|
||||
Update("PropertyValues").
|
||||
Set("DeleteAt", model.GetMillis()).
|
||||
Where(sq.Eq{"FieldID": fieldID})
|
||||
|
||||
if groupID != "" {
|
||||
builder = builder.Where(sq.Eq{"GroupID": groupID})
|
||||
}
|
||||
|
||||
if _, err := s.GetMaster().ExecBuilder(builder); err != nil {
|
||||
return errors.Wrap(err, "property_value_delete_for_field_exec")
|
||||
}
|
||||
|
||||
@@ -1108,7 +1108,7 @@ type PropertyValueStore interface {
|
||||
Update(groupID string, values []*model.PropertyValue) ([]*model.PropertyValue, error)
|
||||
Upsert(values []*model.PropertyValue) ([]*model.PropertyValue, error)
|
||||
Delete(groupID string, id string) error
|
||||
DeleteForField(id string) error
|
||||
DeleteForField(groupID, fieldID string) error
|
||||
DeleteForTarget(groupID string, targetType string, targetID string) error
|
||||
}
|
||||
|
||||
|
||||
@@ -62,17 +62,17 @@ func (_m *PropertyValueStore) Delete(groupID string, id string) error {
|
||||
return r0
|
||||
}
|
||||
|
||||
// DeleteForField provides a mock function with given fields: id
|
||||
func (_m *PropertyValueStore) DeleteForField(id string) error {
|
||||
ret := _m.Called(id)
|
||||
// DeleteForField provides a mock function with given fields: groupID, fieldID
|
||||
func (_m *PropertyValueStore) DeleteForField(groupID string, fieldID string) error {
|
||||
ret := _m.Called(groupID, fieldID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeleteForField")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string) error); ok {
|
||||
r0 = rf(id)
|
||||
if rf, ok := ret.Get(0).(func(string, string) error); ok {
|
||||
r0 = rf(groupID, fieldID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
@@ -933,54 +933,213 @@ func testCreatePropertyValueWithArray(t *testing.T, _ request.CTX, ss store.Stor
|
||||
}
|
||||
|
||||
func testDeleteForField(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
fieldID := model.NewId()
|
||||
groupID := model.NewId()
|
||||
t.Run("should delete values with matching fieldID and groupID", func(t *testing.T) {
|
||||
fieldID := model.NewId()
|
||||
groupID := model.NewId()
|
||||
|
||||
// Create test values
|
||||
value1 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"value 1"`),
|
||||
}
|
||||
// Create test values
|
||||
value1 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"value 1"`),
|
||||
}
|
||||
|
||||
value2 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"value 2"`),
|
||||
}
|
||||
value2 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"value 2"`),
|
||||
}
|
||||
|
||||
value3 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: model.NewId(), // Different field ID
|
||||
Value: json.RawMessage(`"value 3"`),
|
||||
}
|
||||
value3 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID,
|
||||
FieldID: model.NewId(), // Different field ID
|
||||
Value: json.RawMessage(`"value 3"`),
|
||||
}
|
||||
|
||||
for _, value := range []*model.PropertyValue{value1, value2, value3} {
|
||||
_, err := ss.PropertyValue().Create(value)
|
||||
for _, value := range []*model.PropertyValue{value1, value2, value3} {
|
||||
_, err := ss.PropertyValue().Create(value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Delete values for the field
|
||||
err := ss.PropertyValue().DeleteForField(groupID, fieldID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Delete values for the field
|
||||
err := ss.PropertyValue().DeleteForField(fieldID)
|
||||
require.NoError(t, err)
|
||||
// Verify values were soft-deleted
|
||||
deletedValues, err := ss.PropertyValue().GetMany(groupID, []string{value1.ID, value2.ID})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, deletedValues, 2)
|
||||
require.NotZero(t, deletedValues[0].DeleteAt)
|
||||
require.NotZero(t, deletedValues[1].DeleteAt)
|
||||
|
||||
// Verify values were soft-deleted
|
||||
deletedValues, err := ss.PropertyValue().GetMany(groupID, []string{value1.ID, value2.ID})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, deletedValues, 2)
|
||||
require.NotZero(t, deletedValues[0].DeleteAt)
|
||||
require.NotZero(t, deletedValues[1].DeleteAt)
|
||||
// Verify value with different field ID was not deleted
|
||||
nonDeletedValue, err := ss.PropertyValue().Get(groupID, value3.ID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, nonDeletedValue.DeleteAt)
|
||||
})
|
||||
|
||||
// Verify value with different field ID was not deleted
|
||||
nonDeletedValue, err := ss.PropertyValue().Get(groupID, value3.ID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, nonDeletedValue.DeleteAt)
|
||||
t.Run("should not delete values with non-matching groupID", func(t *testing.T) {
|
||||
fieldID := model.NewId()
|
||||
groupID1 := model.NewId()
|
||||
groupID2 := model.NewId()
|
||||
|
||||
// Create values with same fieldID but different groupIDs
|
||||
value1 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID1,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"group1 value"`),
|
||||
}
|
||||
|
||||
value2 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID2,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"group2 value"`),
|
||||
}
|
||||
|
||||
for _, value := range []*model.PropertyValue{value1, value2} {
|
||||
_, err := ss.PropertyValue().Create(value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Delete values for the field but only in groupID1
|
||||
err := ss.PropertyValue().DeleteForField(groupID1, fieldID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify value1 was deleted
|
||||
deletedValue, err := ss.PropertyValue().Get(groupID1, value1.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, deletedValue.DeleteAt)
|
||||
|
||||
// Verify value2 was not deleted (different group)
|
||||
nonDeletedValue, err := ss.PropertyValue().Get(groupID2, value2.ID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, nonDeletedValue.DeleteAt)
|
||||
})
|
||||
|
||||
t.Run("should delete values with empty groupID", func(t *testing.T) {
|
||||
fieldID := model.NewId()
|
||||
groupID1 := model.NewId()
|
||||
groupID2 := model.NewId()
|
||||
|
||||
// Create values with same fieldID but different groupIDs
|
||||
value1 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID1,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"group1 value 2"`),
|
||||
}
|
||||
|
||||
value2 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID2,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"group2 value 2"`),
|
||||
}
|
||||
|
||||
for _, value := range []*model.PropertyValue{value1, value2} {
|
||||
_, err := ss.PropertyValue().Create(value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Delete values for the field across all groups (empty groupID)
|
||||
err := ss.PropertyValue().DeleteForField("", fieldID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify both values were deleted
|
||||
opts := model.PropertyValueSearchOpts{
|
||||
FieldID: fieldID,
|
||||
IncludeDeleted: true,
|
||||
PerPage: 10,
|
||||
}
|
||||
|
||||
values, err := ss.PropertyValue().SearchPropertyValues(opts)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Find our two values within the results
|
||||
var foundValues []*model.PropertyValue
|
||||
for _, v := range values {
|
||||
if v.ID == value1.ID || v.ID == value2.ID {
|
||||
foundValues = append(foundValues, v)
|
||||
}
|
||||
}
|
||||
|
||||
require.Len(t, foundValues, 2)
|
||||
for _, v := range foundValues {
|
||||
require.NotZero(t, v.DeleteAt, "Value should be deleted")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("should work with multiple calls targeting different groups", func(t *testing.T) {
|
||||
fieldID := model.NewId()
|
||||
groupID1 := model.NewId()
|
||||
groupID2 := model.NewId()
|
||||
groupID3 := model.NewId()
|
||||
|
||||
// Create values with same fieldID across multiple groups
|
||||
value1 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID1,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"multi-group test 1"`),
|
||||
}
|
||||
|
||||
value2 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID2,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"multi-group test 2"`),
|
||||
}
|
||||
|
||||
value3 := &model.PropertyValue{
|
||||
TargetID: model.NewId(),
|
||||
TargetType: "test_type",
|
||||
GroupID: groupID3,
|
||||
FieldID: fieldID,
|
||||
Value: json.RawMessage(`"multi-group test 3"`),
|
||||
}
|
||||
|
||||
for _, value := range []*model.PropertyValue{value1, value2, value3} {
|
||||
_, err := ss.PropertyValue().Create(value)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Delete values for the field but only in groupID1
|
||||
err := ss.PropertyValue().DeleteForField(groupID1, fieldID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Delete values for the field but only in groupID2
|
||||
err = ss.PropertyValue().DeleteForField(groupID2, fieldID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify value1 was deleted
|
||||
value1Result, err := ss.PropertyValue().Get(groupID1, value1.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, value1Result.DeleteAt)
|
||||
|
||||
// Verify value2 was deleted
|
||||
value2Result, err := ss.PropertyValue().Get(groupID2, value2.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, value2Result.DeleteAt)
|
||||
|
||||
// Verify value3 was not deleted
|
||||
value3Result, err := ss.PropertyValue().Get(groupID3, value3.ID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, value3Result.DeleteAt)
|
||||
})
|
||||
}
|
||||
|
||||
func testDeleteForTarget(t *testing.T, _ request.CTX, ss store.Store) {
|
||||
|
||||
@@ -7493,10 +7493,10 @@ func (s *TimerLayerPropertyValueStore) Delete(groupID string, id string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *TimerLayerPropertyValueStore) DeleteForField(id string) error {
|
||||
func (s *TimerLayerPropertyValueStore) DeleteForField(groupID string, fieldID string) error {
|
||||
start := time.Now()
|
||||
|
||||
err := s.PropertyValueStore.DeleteForField(id)
|
||||
err := s.PropertyValueStore.DeleteForField(groupID, fieldID)
|
||||
|
||||
elapsed := float64(time.Since(start)) / float64(time.Second)
|
||||
if s.Root.Metrics != nil {
|
||||
|
||||
Ссылка в новой задаче
Block a user