Add support for postgres GROUPING SET, ROLLUP and CUBE grouping operators

Add support for mysql WITH ROLLUP grouping operator
Add support for GROUPING operator
This commit is contained in:
go-jet 2023-03-28 13:16:57 +02:00
parent 31dc7b6dd3
commit fa69565dbf
9 changed files with 476 additions and 70 deletions

View file

@ -12,7 +12,7 @@ func OR(expressions ...BoolExpression) BoolExpression {
return newBoolExpressionListOperator("OR", expressions...)
}
// ROW is construct one table row from list of expressions.
// ROW function is used to create a tuple value that consists of a set of expressions or column values.
func ROW(expressions ...Expression) Expression {
return NewFunc("ROW", expressions, nil)
}
@ -602,16 +602,16 @@ func LEAST(value Expression, values ...Expression) Expression {
type funcExpressionImpl struct {
ExpressionInterfaceImpl
name string
expressions []Expression
noBrackets bool
name string
parameters parametersSerializer
noBrackets bool
}
// NewFunc creates new function with name and expressions parameters
func NewFunc(name string, expressions []Expression, parent Expression) *funcExpressionImpl {
funcExp := &funcExpressionImpl{
name: name,
expressions: parameters(expressions),
name: name,
parameters: parametersSerializer(expressions),
}
if parent != nil {
@ -623,18 +623,43 @@ func NewFunc(name string, expressions []Expression, parent Expression) *funcExpr
return funcExp
}
func parameters(expressions []Expression) []Expression {
var ret []Expression
for _, expression := range expressions {
if _, isStatement := expression.(Statement); isStatement {
ret = append(ret, expression)
} else {
ret = append(ret, skipWrap(expression))
}
func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil {
serializeOverrideFunc := serializeOverride(ExpressionListToSerializerList(f.parameters)...)
serializeOverrideFunc(statement, out, FallTrough(options)...)
return
}
return ret
addBrackets := !f.noBrackets || len(f.parameters) > 0
if addBrackets {
out.WriteString(f.name + "(")
} else {
out.WriteString(f.name)
}
f.parameters.serialize(statement, out, options...)
if addBrackets {
out.WriteString(")")
}
}
type parametersSerializer []Expression
func (p parametersSerializer) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
for i, expression := range p {
if i > 0 {
out.WriteString(", ")
}
if _, isStatement := expression.(Statement); isStatement {
expression.serialize(statement, out, options...)
} else {
skipWrap(expression).serialize(statement, out, options...)
}
}
}
// NewFloatWindowFunc creates new float function with name and expressions
@ -646,28 +671,6 @@ func newWindowFunc(name string, expressions ...Expression) windowExpression {
return windowExpr
}
func (f *funcExpressionImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
if serializeOverride := out.Dialect.FunctionSerializeOverride(f.name); serializeOverride != nil {
serializeOverrideFunc := serializeOverride(ExpressionListToSerializerList(f.expressions)...)
serializeOverrideFunc(statement, out, FallTrough(options)...)
return
}
addBrackets := !f.noBrackets || len(f.expressions) > 0
if addBrackets {
out.WriteString(f.name + "(")
} else {
out.WriteString(f.name)
}
serializeExpressionList(statement, f.expressions, ", ", out)
if addBrackets {
out.WriteString(")")
}
}
type boolFunc struct {
funcExpressionImpl
boolInterfaceImpl

View file

@ -4,3 +4,38 @@ package jet
type GroupByClause interface {
serializeForGroupBy(statement StatementType, out *SQLBuilder)
}
// GROUPING_SETS operator allows grouping of the rows in a table by multiple sets of columns in a single query.
// This can be useful when we want to analyze data by different combinations of columns, without having to write separate
// queries for each combination.
func GROUPING_SETS(expressions ...Expression) GroupByClause {
return Func("GROUPING SETS", expressions...)
}
// ROLLUP operator is used with the GROUP BY clause to generate all prefixes of a group of columns including the empty list.
// It creates extra rows in the result set that represent the subtotal values for each combination of columns.
func ROLLUP(expressions ...Expression) GroupByClause {
return Func("ROLLUP", expressions...)
}
// CUBE operator is used with the GROUP BY clause to generate subtotals for all possible combinations of a group of columns.
// It creates extra rows in the result set that represent the subtotal values for each combination of columns.
func CUBE(expressions ...Expression) GroupByClause {
return Func("CUBE", expressions...)
}
// GROUPING function is used to identify which columns are included in a grouping set or a subtotal row. It takes as input
// the name of a column and returns 1 if the column is not included in the current grouping set, and 0 otherwise.
// It can be also used with multiple parameters to check if a set of columns is included in the current grouping set. The result
// of the GROUPING function would then be an integer bit mask having 1s for the arguments which have GROUPING(argument) as 1.
func GROUPING(expressions ...Expression) IntegerExpression {
return IntExp(Func("GROUPING", expressions...))
}
// WITH_ROLLUP operator is used with the GROUP BY clause to generate all prefixes of a group of columns including the empty list.
// It creates extra rows in the result set that represent the subtotal values for each combination of columns.
func WITH_ROLLUP(expressions ...Expression) GroupByClause {
return newCustomExpression(
parametersSerializer(expressions), Token("WITH ROLLUP"),
)
}

View file

@ -386,7 +386,7 @@ func (n *wrap) serialize(statementType StatementType, out *SQLBuilder, options .
out.WriteString(")")
}
// WRAP wraps list of expressions with brackets '(' and ')'
// WRAP wraps list of expressions with brackets - ( expression1, expression2, ... )
func WRAP(expression ...Expression) Expression {
wrap := &wrap{expressions: expression}
wrap.ExpressionInterfaceImpl.Parent = wrap