Files
releases/vendor/github.com/huandu/go-sqlbuilder/cte.go
T
Stephan Renatus 4ab2ac0c61 Port Compile API extensions from EOPA (#7887)
* server: port compile API

Also adds e2e tests: These include coverage for ucast in the prisma
setting, and thus require some JS runtime.

* e2e: selectively skip e2e Compile API tests

...for macos runs, and for the go-compat suites.

* server: accept timer_rego_external_resolve_ns metrics with value 0

When running the tests in a loop for a while, I would see values of 0ns
for this metric. However, comparing with its non-zero values, which are
often 41 or 42ns, it seems like this is just not happening in this code
path. So if "almost nothing" actually goes below 1ns, it's OK.

* e2e: split dep-heavy e2e tests into their own go module
* Makefile: export DOCKER_RUNNING (make e2e read it)

---------

Co-authored-by: Philip Conrad <philip@chariot-chaser.net>
Signed-off-by: Stephan Renatus <stephan.renatus@gmail.com>
2025-09-22 12:11:06 +02:00

168 lines
4.5 KiB
Go

// Copyright 2024 Huan Du. All rights reserved.
// Licensed under the MIT license that can be found in the LICENSE file.
package sqlbuilder
const (
cteMarkerInit injectionMarker = iota
cteMarkerAfterWith
)
// With creates a new CTE builder with default flavor.
func With(tables ...*CTEQueryBuilder) *CTEBuilder {
return DefaultFlavor.NewCTEBuilder().With(tables...)
}
// WithRecursive creates a new recursive CTE builder with default flavor.
func WithRecursive(tables ...*CTEQueryBuilder) *CTEBuilder {
return DefaultFlavor.NewCTEBuilder().WithRecursive(tables...)
}
func newCTEBuilder() *CTEBuilder {
return &CTEBuilder{
args: &Args{},
injection: newInjection(),
}
}
// CTEBuilder is a CTE (Common Table Expression) builder.
type CTEBuilder struct {
recursive bool
queries []*CTEQueryBuilder
queryBuilderVars []string
args *Args
injection *injection
marker injectionMarker
}
var _ Builder = new(CTEBuilder)
// With sets the CTE name and columns.
func (cteb *CTEBuilder) With(queries ...*CTEQueryBuilder) *CTEBuilder {
queryBuilderVars := make([]string, 0, len(queries))
for _, query := range queries {
queryBuilderVars = append(queryBuilderVars, cteb.args.Add(query))
}
cteb.queries = queries
cteb.queryBuilderVars = queryBuilderVars
cteb.marker = cteMarkerAfterWith
return cteb
}
// WithRecursive sets the CTE name and columns and turns on the RECURSIVE keyword.
func (cteb *CTEBuilder) WithRecursive(queries ...*CTEQueryBuilder) *CTEBuilder {
cteb.With(queries...).recursive = true
return cteb
}
// Select creates a new SelectBuilder to build a SELECT statement using this CTE.
func (cteb *CTEBuilder) Select(col ...string) *SelectBuilder {
sb := cteb.args.Flavor.NewSelectBuilder()
return sb.With(cteb).Select(col...)
}
// DeleteFrom creates a new DeleteBuilder to build a DELETE statement using this CTE.
func (cteb *CTEBuilder) DeleteFrom(table string) *DeleteBuilder {
db := cteb.args.Flavor.NewDeleteBuilder()
return db.With(cteb).DeleteFrom(table)
}
// Update creates a new UpdateBuilder to build an UPDATE statement using this CTE.
func (cteb *CTEBuilder) Update(table string) *UpdateBuilder {
ub := cteb.args.Flavor.NewUpdateBuilder()
return ub.With(cteb).Update(table)
}
// String returns the compiled CTE string.
func (cteb *CTEBuilder) String() string {
sql, _ := cteb.Build()
return sql
}
// Build returns compiled CTE string and args.
func (cteb *CTEBuilder) Build() (sql string, args []interface{}) {
return cteb.BuildWithFlavor(cteb.args.Flavor)
}
// BuildWithFlavor builds a CTE with the specified flavor and initial arguments.
func (cteb *CTEBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
buf := newStringBuilder()
cteb.injection.WriteTo(buf, cteMarkerInit)
if len(cteb.queryBuilderVars) > 0 {
buf.WriteLeadingString("WITH ")
if cteb.recursive {
buf.WriteString("RECURSIVE ")
}
buf.WriteStrings(cteb.queryBuilderVars, ", ")
}
cteb.injection.WriteTo(buf, cteMarkerAfterWith)
return cteb.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
}
// SetFlavor sets the flavor of compiled sql.
func (cteb *CTEBuilder) SetFlavor(flavor Flavor) (old Flavor) {
old = cteb.args.Flavor
cteb.args.Flavor = flavor
return
}
// Flavor returns flavor of builder
func (cteb *CTEBuilder) Flavor() Flavor {
return cteb.args.Flavor
}
// SQL adds an arbitrary sql to current position.
func (cteb *CTEBuilder) SQL(sql string) *CTEBuilder {
cteb.injection.SQL(cteb.marker, sql)
return cteb
}
// TableNames returns all table names in a CTE.
func (cteb *CTEBuilder) TableNames() []string {
if len(cteb.queryBuilderVars) == 0 {
return nil
}
tableNames := make([]string, 0, len(cteb.queries))
for _, query := range cteb.queries {
tableNames = append(tableNames, query.TableName())
}
return tableNames
}
// tableNamesForFrom returns a list of table names which should be automatically added to FROM clause.
// It's not public, as this feature is designed only for SelectBuilder/UpdateBuilder/DeleteBuilder right now.
func (cteb *CTEBuilder) tableNamesForFrom() []string {
cnt := 0
// ShouldAddToTableList() unlikely returns true.
// Count it before allocating any memory for better performance.
for _, query := range cteb.queries {
if query.ShouldAddToTableList() {
cnt++
}
}
if cnt == 0 {
return nil
}
tableNames := make([]string, 0, cnt)
for _, query := range cteb.queries {
if query.ShouldAddToTableList() {
tableNames = append(tableNames, query.TableName())
}
}
return tableNames
}