动态条件构建器

huangapple go评论119阅读模式
英文:

Dynamic ConditionBuilder

问题

我的问题非常简单,我想动态创建过滤器并在查询输入中使用它。我必须明确指出,tf变量不能改变。

所以这是我做的:

totalFilter := expression.ConditionBuilder{}
filter := expression.Name("status").Equal(expression.Value("0"))
filter2 := expression.Name("foo").Equal(expression.Value("bar"))
filter3 := expression.Name("yes").Equal(expression.Value("no"))
tf := []expression.ConditionBuilder{filter, filter2, filter3}
for _, v := range tf {
totalFilter = totalFilter.And(v)
}
expr := expression.NewBuilder().WithFilter(totalFilter)
builder, err := expr.Build()
if err != nil {
log.Println(err)
return err
}

但问题是totalFilter是一个空结构体,所以它的mode变量等于0,然后引发警报,因为mode 0是unsetCond。

我找到的唯一解决方法是这样做:

for i, v := range tf {
if i == 0 {
totalFilter = v
} else {
totalFilter.And(v)
}
}

但我想知道是否还有其他解决方案。

英文:

My problem is pretty simple, I would like to dynamically create filters to use it in my query input.
I must precise that the tf variable can't change.

So here is what I did :

  1. totalFilter := expression.ConditionBuilder{}
  2. filter := expression.Name("status").Equal(expression.Value("0"))
  3. filter2 := expression.Name("foo").Equal(expression.Value("bar"))
  4. filter3 := expression.Name("yes").Equal(expression.Value("no"))
  5. tf := []expression.ConditionBuilder{filter, filter2, filter3}
  6. for _, v := range tf {
  7. totalFilter = totalFilter.And(v)
  8. }
  9. expr := expression.NewBuilder().WithFilter(totalFilter)
  10. builder, err := expr.Build()
  11. if err != nil {
  12. log.Println(err)
  13. return err
  14. }

But the probleme is that totalFilter is an empty struct so it's mode variable is equal to 0 and then it raise an alert because mode 0 is unsetCond.

The only workaround that I found is to do this :

  1. for i, v := range tf {
  2. if i == 0 {
  3. totalFilter = v
  4. } else {
  5. totalFilter.And(v)
  6. }
  7. }

But I was wondering if there is another solution.

答案1

得分: 1

你可以通过创建一个自定义的可变参数函数来抽象化对第一个expression.ConditionBuilder的处理,该函数至少需要一个expression.ConditionBuilder参数:

  1. func And(first expression.ConditionBuilder, rest ...expression.ConditionBuilder) expression.ConditionBuilder {
  2. result := first
  3. for _, cb := range rest {
  4. result = result.And(cb)
  5. }
  6. return result
  7. }

然后,在main函数中使用:

  1. filter := expression.Name("status").Equal(expression.Value("0"))
  2. filter2 := expression.Name("foo").Equal(expression.Value("bar"))
  3. filter3 := expression.Name("yes").Equal(expression.Value("no"))
  4. totalFilter := And(filter, filter2, filter3)
  5. expr := expression.NewBuilder().WithFilter(totalFilter)
  6. builder, err := expr.Build()
  7. // 其他操作...

请注意,expression包中还导出了一个名为And类似函数,但它需要至少两个(而不仅仅是一个)expression.ConditionBuilder参数。这有点不幸...

英文:

You could abstract away the treatment of the first expression.ConditionBuilder in a custom variadic function taking at least one expression.ConditionBuilder parameter:

  1. func And(first expression.ConditionBuilder, rest ...expression.ConditionBuilder) expression.ConditionBuilder {
  2. result := first
  3. for _, cb := range rest {
  4. result = result.And(cb)
  5. }
  6. return result
  7. }

Then, in main:

  1. filter := expression.Name("status").Equal(expression.Value("0"))
  2. filter2 := expression.Name("foo").Equal(expression.Value("bar"))
  3. filter3 := expression.Name("yes").Equal(expression.Value("no"))
  4. totalFilter := And(filter, filter2, filter3)
  5. expr := expression.NewBuilder().WithFilter(totalFilter)
  6. builder, err := expr.Build()
  7. // etc.

Note that a similar function, also named And, is exported by the expression package, but it takes at least two (not just one) expression.ConditionBuilder parameters. That's unfortunate...

答案2

得分: 0

我的方法是创建一个“虚拟”条件,它始终返回true,就像动态SQL语句中常见的WHERE 1=1 [AND ...]条件一样。

示例代码将变为:

  1. // 虚拟条件 (1=1) 用于初始化过滤器
  2. totalFilter := expression.Equal(expression.Value(1), expression.Value(1))
  3. filter := expression.Name("status").Equal(expression.Value("0"))
  4. filter2 := expression.Name("foo").Equal(expression.Value("bar"))
  5. filter3 := expression.Name("yes").Equal(expression.Value("no"))
  6. tf := []expression.ConditionBuilder{filter, filter2, filter3}
  7. for _, v := range tf {
  8. totalFilter = totalFilter.And(v)
  9. }
  10. expr := expression.NewBuilder().WithFilter(totalFilter)
  11. builder, err := expr.Build()
  12. if err != nil {
  13. log.Println(err)
  14. return err
  15. }

请注意,如果您的其他条件是通过“OR”操作连接的,则虚拟条件需要被反转,以便始终返回false。

英文:

My approach was to create a "dummy" condition that will always return true, much like the WHERE 1=1 [AND ...] condition that is common in dynamic SQL statements.

The example code would become:

  1. // dummy condition (1=1) to initialize the filter
  2. totalFilter := expression.Equal(expression.Value(1), expression.Value(1))
  3. filter := expression.Name("status").Equal(expression.Value("0"))
  4. filter2 := expression.Name("foo").Equal(expression.Value("bar"))
  5. filter3 := expression.Name("yes").Equal(expression.Value("no"))
  6. tf := []expression.ConditionBuilder{filter, filter2, filter3}
  7. for _, v := range tf {
  8. totalFilter = totalFilter.And(v)
  9. }
  10. expr := expression.NewBuilder().WithFilter(totalFilter)
  11. builder, err := expr.Build()
  12. if err != nil {
  13. log.Println(err)
  14. return err
  15. }

Note that if your other conditions are joined by an OR operation, the dummy condition would need to be inverted so that it always returns false.

huangapple
  • 本文由 发表于 2021年6月4日 18:58:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/67836059.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定