mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-13 03:42:35 -06:00
4ab2ac0c61
* 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>
247 lines
6.3 KiB
Go
247 lines
6.3 KiB
Go
// Copyright 2018 Huan Du. All rights reserved.
|
|
// Licensed under the MIT license that can be found in the LICENSE file.
|
|
|
|
package sqlbuilder
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
insertMarkerInit injectionMarker = iota
|
|
insertMarkerAfterInsertInto
|
|
insertMarkerAfterCols
|
|
insertMarkerAfterValues
|
|
insertMarkerAfterSelect
|
|
insertMarkerAfterReturning
|
|
)
|
|
|
|
// NewInsertBuilder creates a new INSERT builder.
|
|
func NewInsertBuilder() *InsertBuilder {
|
|
return DefaultFlavor.NewInsertBuilder()
|
|
}
|
|
|
|
func newInsertBuilder() *InsertBuilder {
|
|
args := &Args{}
|
|
return &InsertBuilder{
|
|
verb: "INSERT",
|
|
args: args,
|
|
injection: newInjection(),
|
|
}
|
|
}
|
|
|
|
// InsertBuilder is a builder to build INSERT.
|
|
type InsertBuilder struct {
|
|
verb string
|
|
table string
|
|
cols []string
|
|
values [][]string
|
|
returning []string
|
|
|
|
args *Args
|
|
|
|
injection *injection
|
|
marker injectionMarker
|
|
|
|
sbHolder string
|
|
}
|
|
|
|
var _ Builder = new(InsertBuilder)
|
|
|
|
// InsertInto sets table name in INSERT.
|
|
func InsertInto(table string) *InsertBuilder {
|
|
return DefaultFlavor.NewInsertBuilder().InsertInto(table)
|
|
}
|
|
|
|
// InsertInto sets table name in INSERT.
|
|
func (ib *InsertBuilder) InsertInto(table string) *InsertBuilder {
|
|
ib.table = Escape(table)
|
|
ib.marker = insertMarkerAfterInsertInto
|
|
return ib
|
|
}
|
|
|
|
// InsertIgnoreInto sets table name in INSERT IGNORE.
|
|
func InsertIgnoreInto(table string) *InsertBuilder {
|
|
return DefaultFlavor.NewInsertBuilder().InsertIgnoreInto(table)
|
|
}
|
|
|
|
// InsertIgnoreInto sets table name in INSERT IGNORE.
|
|
func (ib *InsertBuilder) InsertIgnoreInto(table string) *InsertBuilder {
|
|
ib.args.Flavor.PrepareInsertIgnore(table, ib)
|
|
return ib
|
|
}
|
|
|
|
// ReplaceInto sets table name and changes the verb of ib to REPLACE.
|
|
// REPLACE INTO is a MySQL extension to the SQL standard.
|
|
func ReplaceInto(table string) *InsertBuilder {
|
|
return DefaultFlavor.NewInsertBuilder().ReplaceInto(table)
|
|
}
|
|
|
|
// ReplaceInto sets table name and changes the verb of ib to REPLACE.
|
|
// REPLACE INTO is a MySQL extension to the SQL standard.
|
|
func (ib *InsertBuilder) ReplaceInto(table string) *InsertBuilder {
|
|
ib.verb = "REPLACE"
|
|
ib.table = Escape(table)
|
|
ib.marker = insertMarkerAfterInsertInto
|
|
return ib
|
|
}
|
|
|
|
// Cols sets columns in INSERT.
|
|
func (ib *InsertBuilder) Cols(col ...string) *InsertBuilder {
|
|
ib.cols = EscapeAll(col...)
|
|
ib.marker = insertMarkerAfterCols
|
|
return ib
|
|
}
|
|
|
|
// Select returns a new SelectBuilder to build a SELECT statement inside the INSERT INTO.
|
|
func (isb *InsertBuilder) Select(col ...string) *SelectBuilder {
|
|
sb := Select(col...)
|
|
isb.sbHolder = isb.args.Add(sb)
|
|
return sb
|
|
}
|
|
|
|
// Values adds a list of values for a row in INSERT.
|
|
func (ib *InsertBuilder) Values(value ...interface{}) *InsertBuilder {
|
|
placeholders := make([]string, 0, len(value))
|
|
|
|
for _, v := range value {
|
|
placeholders = append(placeholders, ib.args.Add(v))
|
|
}
|
|
|
|
ib.values = append(ib.values, placeholders)
|
|
ib.marker = insertMarkerAfterValues
|
|
return ib
|
|
}
|
|
|
|
// Returning sets returning columns.
|
|
// For DBMS that doesn't support RETURNING, e.g. MySQL, it will be ignored.
|
|
func (ib *InsertBuilder) Returning(col ...string) *InsertBuilder {
|
|
ib.returning = col
|
|
ib.marker = insertMarkerAfterReturning
|
|
return ib
|
|
}
|
|
|
|
// NumValue returns the number of values to insert.
|
|
func (ib *InsertBuilder) NumValue() int {
|
|
return len(ib.values)
|
|
}
|
|
|
|
// String returns the compiled INSERT string.
|
|
func (ib *InsertBuilder) String() string {
|
|
s, _ := ib.Build()
|
|
return s
|
|
}
|
|
|
|
// Build returns compiled INSERT string and args.
|
|
// They can be used in `DB#Query` of package `database/sql` directly.
|
|
func (ib *InsertBuilder) Build() (sql string, args []interface{}) {
|
|
return ib.BuildWithFlavor(ib.args.Flavor)
|
|
}
|
|
|
|
// BuildWithFlavor returns compiled INSERT string and args with flavor and initial args.
|
|
// They can be used in `DB#Query` of package `database/sql` directly.
|
|
func (ib *InsertBuilder) BuildWithFlavor(flavor Flavor, initialArg ...interface{}) (sql string, args []interface{}) {
|
|
buf := newStringBuilder()
|
|
ib.injection.WriteTo(buf, insertMarkerInit)
|
|
|
|
if len(ib.values) > 1 && ib.args.Flavor == Oracle {
|
|
buf.WriteLeadingString(ib.verb)
|
|
buf.WriteString(" ALL")
|
|
|
|
for _, v := range ib.values {
|
|
if len(ib.table) > 0 {
|
|
buf.WriteString(" INTO ")
|
|
buf.WriteString(ib.table)
|
|
}
|
|
ib.injection.WriteTo(buf, insertMarkerAfterInsertInto)
|
|
if len(ib.cols) > 0 {
|
|
buf.WriteLeadingString("(")
|
|
buf.WriteStrings(ib.cols, ", ")
|
|
buf.WriteString(")")
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterCols)
|
|
}
|
|
|
|
buf.WriteLeadingString("VALUES ")
|
|
values := make([]string, 0, len(ib.values))
|
|
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
|
|
buf.WriteStrings(values, ", ")
|
|
}
|
|
|
|
buf.WriteString(" SELECT 1 from DUAL")
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterValues)
|
|
|
|
return ib.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
|
|
}
|
|
|
|
if len(ib.table) > 0 {
|
|
buf.WriteLeadingString(ib.verb)
|
|
buf.WriteString(" INTO ")
|
|
buf.WriteString(ib.table)
|
|
}
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterInsertInto)
|
|
|
|
if len(ib.cols) > 0 {
|
|
buf.WriteLeadingString("(")
|
|
buf.WriteStrings(ib.cols, ", ")
|
|
buf.WriteString(")")
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterCols)
|
|
}
|
|
|
|
if ib.sbHolder != "" {
|
|
buf.WriteString(" ")
|
|
buf.WriteString(ib.sbHolder)
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterSelect)
|
|
} else if len(ib.values) > 0 {
|
|
buf.WriteLeadingString("VALUES ")
|
|
values := make([]string, 0, len(ib.values))
|
|
|
|
for _, v := range ib.values {
|
|
values = append(values, fmt.Sprintf("(%v)", strings.Join(v, ", ")))
|
|
}
|
|
|
|
buf.WriteStrings(values, ", ")
|
|
}
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterValues)
|
|
|
|
if flavor == PostgreSQL || flavor == SQLite {
|
|
if len(ib.returning) > 0 {
|
|
buf.WriteLeadingString("RETURNING ")
|
|
buf.WriteStrings(ib.returning, ", ")
|
|
}
|
|
|
|
ib.injection.WriteTo(buf, insertMarkerAfterReturning)
|
|
}
|
|
|
|
return ib.args.CompileWithFlavor(buf.String(), flavor, initialArg...)
|
|
}
|
|
|
|
// SetFlavor sets the flavor of compiled sql.
|
|
func (ib *InsertBuilder) SetFlavor(flavor Flavor) (old Flavor) {
|
|
old = ib.args.Flavor
|
|
ib.args.Flavor = flavor
|
|
return
|
|
}
|
|
|
|
// Flavor returns flavor of builder
|
|
func (ib *InsertBuilder) Flavor() Flavor {
|
|
return ib.args.Flavor
|
|
}
|
|
|
|
// Var returns a placeholder for value.
|
|
func (ib *InsertBuilder) Var(arg interface{}) string {
|
|
return ib.args.Add(arg)
|
|
}
|
|
|
|
// SQL adds an arbitrary sql to current position.
|
|
func (ib *InsertBuilder) SQL(sql string) *InsertBuilder {
|
|
ib.injection.SQL(ib.marker, sql)
|
|
return ib
|
|
}
|