动态条件构建器

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

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 :

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
}

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 :

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

But I was wondering if there is another solution.

答案1

得分: 1

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

func And(first expression.ConditionBuilder, rest ...expression.ConditionBuilder) expression.ConditionBuilder {
    result := first
    for _, cb := range rest {
        result = result.And(cb)
    }
    return result
}

然后,在main函数中使用:

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

请注意,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:

func And(first expression.ConditionBuilder, rest ...expression.ConditionBuilder) expression.ConditionBuilder {
	result := first
	for _, cb := range rest {
		result = result.And(cb)
	}
	return result
}

Then, in main:

filter := expression.Name("status").Equal(expression.Value("0"))
filter2 := expression.Name("foo").Equal(expression.Value("bar"))
filter3 := expression.Name("yes").Equal(expression.Value("no"))
totalFilter := And(filter, filter2, filter3)
expr := expression.NewBuilder().WithFilter(totalFilter)
builder, err := expr.Build()
// 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) 用于初始化过滤器
totalFilter := expression.Equal(expression.Value(1), expression.Value(1))

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
}

请注意,如果您的其他条件是通过“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:

// dummy condition (1=1) to initialize the filter
totalFilter := expression.Equal(expression.Value(1), expression.Value(1))

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
}

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:

确定