diff --git a/README.md b/README.md index ea88848..2cbdcdb 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ you have 2 options: - `TaggedOnly()`: Will only change queries on fields that have the `gormlike:"true"` tag - `SettingOnly()`: Will only change queries on `*gorm.DB` objects that have `.Set("gormlike", true)` set. -If you want a particular query to not be like-able, use `.Set("gormlike", false)`. This works +If you want a particular query or field to not be like-able, use `.Set("gormlike", false)` or `gormlike:"false"` respectively. These work regardless of configuration. ## 💡 Related Libraries diff --git a/query.go b/query.go index f4b4902..5f52ced 100644 --- a/query.go +++ b/query.go @@ -30,22 +30,26 @@ func (d *gormLike) queryCallback(db *gorm.DB) { for index, cond := range exp.Exprs { switch cond := cond.(type) { case clause.Eq: - if d.conditionalTag { - columnName, ok := cond.Column.(string) - if !ok { - continue - } + columnName, columnOk := cond.Column.(string) + if !columnOk { + continue + } - value := db.Statement.Schema.FieldsByDBName[columnName].Tag.Get(tagName) + // Get the `gormlike` value + tagValue := db.Statement.Schema.FieldsByDBName[columnName].Tag.Get(tagName) - // Ignore if there's no valid tag settingValue - if value != "true" { - continue - } + // If the user has explicitly set this to false, ignore this field + if tagValue == "false" { + continue + } + + // If tags are required and the tag is not true, ignore this field + if d.conditionalTag && tagValue != "true" { + continue } - value, ok := cond.Value.(string) - if !ok { + value, columnOk := cond.Value.(string) + if !columnOk { continue } @@ -62,18 +66,22 @@ func (d *gormLike) queryCallback(db *gorm.DB) { exp.Exprs[index] = db.Session(&gorm.Session{NewDB: true}).Where(condition, value).Statement.Clauses["WHERE"].Expression case clause.IN: - if d.conditionalTag { - columnName, ok := cond.Column.(string) - if !ok { - continue - } + columnName, columnOk := cond.Column.(string) + if !columnOk { + continue + } - value := db.Statement.Schema.FieldsByDBName[columnName].Tag.Get(tagName) + // Get the `gormlike` value + tagValue := db.Statement.Schema.FieldsByDBName[columnName].Tag.Get(tagName) - // Ignore if there's no valid tag settingValue - if value != "true" { - continue - } + // If the user has explicitly set this to false, ignore this field + if tagValue == "false" { + continue + } + + // If tags are required and the tag is not true, ignore this field + if d.conditionalTag && tagValue != "true" { + continue } var likeCounter int diff --git a/query_test.go b/query_test.go index 1203e41..a97ab2a 100644 --- a/query_test.go +++ b/query_test.go @@ -357,6 +357,71 @@ func TestGormLike_Initialize_TriggersLikingCorrectlyWithConditionalTag(t *testin } } +func TestGormLike_Initialize_AlwaysIgnoresFieldsWithGormLikeFalse(t *testing.T) { + t.Parallel() + + type ObjectB struct { + Name string + Other string `gormlike:"false"` + } + + tests := map[string]struct { + filter map[string]any + existing []ObjectB + expected []ObjectB + }{ + "Normal filter works on never field": { + filter: map[string]any{ + "other": "abc", + }, + existing: []ObjectB{{Name: "jessica", Other: "abc"}, {Name: "jessica", Other: "abc"}}, + expected: []ObjectB{{Name: "jessica", Other: "abc"}, {Name: "jessica", Other: "abc"}}, + }, + "simple filter on disallowed fields": { + filter: map[string]any{ + "other": "%b%", + }, + existing: []ObjectB{{Name: "jessica", Other: "abc"}, {Name: "jessica", Other: "abc"}}, + expected: []ObjectB{}, + }, + "multi-filter on disallowed fields": { + filter: map[string]any{ + "other": []string{"%b%", "%c%"}, + }, + existing: []ObjectB{{Name: "jessica", Other: "abc"}, {Name: "jessica", Other: "abc"}}, + expected: []ObjectB{}, + }, + } + + for name, testData := range tests { + testData := testData + t.Run(name, func(t *testing.T) { + t.Parallel() + // Arrange + db := gormtestutil.NewMemoryDatabase(t, gormtestutil.WithName(t.Name())) + _ = db.AutoMigrate(&ObjectB{}) + plugin := New(TaggedOnly()) + + if err := db.CreateInBatches(testData.existing, 10).Error; err != nil { + t.Error(err) + t.FailNow() + } + + // Act + err := db.Use(plugin) + + // Assert + assert.NoError(t, err) + + var actual []ObjectB + err = db.Where(testData.filter).Find(&actual).Error + assert.NoError(t, err) + + assert.Equal(t, testData.expected, actual) + }) + } +} + func TestGormLike_Initialize_TriggersLikingCorrectlyWithSetting(t *testing.T) { t.Parallel()