1
0
mirror of https://github.com/uptrace/go-clickhouse.git synced 2025-06-08 23:26:11 +02:00

feat: add Prewhere

This commit is contained in:
Vladimir Mihailenco 2023-03-29 15:17:19 +03:00
parent e4f2453f97
commit 59dcbc03a4
4 changed files with 128 additions and 76 deletions

View File

@ -32,6 +32,15 @@ type baseQuery struct {
flags internal.Flag
}
func (q *baseQuery) clone() baseQuery {
clone := *q
clone.with = lazyClone(clone.with)
clone.tables = lazyClone(clone.tables)
clone.columns = lazyClone(clone.columns)
clone.settings = lazyClone(clone.settings)
return clone
}
func (q *baseQuery) DB() *DB {
return q.db
}
@ -392,51 +401,32 @@ func appendTableColumns(b []byte, table chschema.Safe, fields []*chschema.Field)
//------------------------------------------------------------------------------
type whereBaseQuery struct {
baseQuery
where []chschema.QueryWithSep
type whereQuery struct {
filters []chschema.QueryWithSep
}
func (q *whereBaseQuery) addWhere(where chschema.QueryWithSep) {
q.where = append(q.where, where)
func (q *whereQuery) clone() whereQuery {
clone := *q
clone.filters = lazyClone(clone.filters)
return clone
}
func (q *whereBaseQuery) addWhereGroup(sep string, where []chschema.QueryWithSep) {
if len(where) == 0 {
func (q *whereQuery) addFilter(filter chschema.QueryWithSep) {
q.filters = append(q.filters, filter)
}
func (q *whereQuery) addGroup(sep string, filters []chschema.QueryWithSep) {
if len(filters) == 0 {
return
}
q.addWhere(chschema.SafeQueryWithSep("", nil, sep))
q.addWhere(chschema.SafeQueryWithSep("", nil, "("))
q.addFilter(chschema.SafeQueryWithSep("", nil, sep))
q.addFilter(chschema.SafeQueryWithSep("", nil, "("))
where[0].Sep = ""
q.where = append(q.where, where...)
filters[0].Sep = ""
q.filters = append(q.filters, filters...)
q.addWhere(chschema.SafeQueryWithSep("", nil, ")"))
}
func (q *whereBaseQuery) mustAppendWhere(fmter chschema.Formatter, b []byte) ([]byte, error) {
if len(q.where) == 0 {
err := errors.New("ch: Update and Delete queries require at least one Where")
return nil, err
}
return q.appendWhere(fmter, b)
}
func (q *whereBaseQuery) appendWhere(fmter chschema.Formatter, b []byte) (_ []byte, err error) {
if len(q.where) == 0 {
return b, nil
}
b = append(b, " WHERE "...)
b, err = appendWhere(fmter, b, q.where)
if err != nil {
return nil, err
}
return b, nil
q.addFilter(chschema.SafeQueryWithSep("", nil, ")"))
}
func appendWhere(
@ -460,3 +450,11 @@ func appendWhere(
}
return b, nil
}
func lazyClone[S ~[]E, E any](s S) S {
// Preserve nil in case it matters.
if s == nil {
return nil
}
return s[:len(s):len(s)]
}

View File

@ -10,17 +10,16 @@ import (
)
type InsertQuery struct {
whereBaseQuery
baseQuery
where whereQuery
}
var _ Query = (*InsertQuery)(nil)
func NewInsertQuery(db *DB) *InsertQuery {
return &InsertQuery{
whereBaseQuery: whereBaseQuery{
baseQuery: baseQuery{
db: db,
},
baseQuery: baseQuery{
db: db,
},
}
}
@ -76,12 +75,12 @@ func (q *InsertQuery) ExcludeColumn(columns ...string) *InsertQuery {
//------------------------------------------------------------------------------
func (q *InsertQuery) Where(query string, args ...any) *InsertQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " AND "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
return q
}
func (q *InsertQuery) WhereOr(query string, args ...any) *InsertQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " OR "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
return q
}
@ -152,10 +151,9 @@ func (q *InsertQuery) appendValues(
return nil, err
}
if len(q.where) > 0 {
if len(q.where.filters) > 0 {
b = append(b, " WHERE "...)
b, err = appendWhere(fmter, b, q.where)
b, err = appendWhere(fmter, b, q.where.filters)
if err != nil {
return nil, err
}

View File

@ -13,11 +13,13 @@ import (
)
type SelectQuery struct {
whereBaseQuery
baseQuery
sample chschema.QueryWithArgs
distinctOn []chschema.QueryWithArgs
joins []joinQuery
prewhere whereQuery
where whereQuery
group []chschema.QueryWithArgs
having []chschema.QueryWithArgs
order []chschema.QueryWithArgs
@ -30,14 +32,28 @@ var _ Query = (*SelectQuery)(nil)
func NewSelectQuery(db *DB) *SelectQuery {
return &SelectQuery{
whereBaseQuery: whereBaseQuery{
baseQuery: baseQuery{
db: db,
},
baseQuery: baseQuery{
db: db,
},
}
}
func (q *SelectQuery) Clone() *SelectQuery {
clone := *q
clone.baseQuery = clone.baseQuery.clone()
clone.prewhere = clone.prewhere.clone()
clone.where = clone.where.clone()
clone.distinctOn = lazyClone(clone.distinctOn)
clone.joins = lazyClone(clone.joins)
clone.group = lazyClone(clone.group)
clone.having = lazyClone(clone.having)
clone.order = lazyClone(clone.order)
return &clone
}
func (q *SelectQuery) Operation() string {
return "SELECT"
}
@ -163,26 +179,52 @@ func (q *SelectQuery) joinOn(cond string, args []any, sep string) *SelectQuery {
//------------------------------------------------------------------------------
func (q *SelectQuery) Prewhere(query string, args ...any) *SelectQuery {
q.prewhere.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
return q
}
func (q *SelectQuery) PrewhereOr(query string, args ...any) *SelectQuery {
q.prewhere.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
return q
}
func (q *SelectQuery) PrewhereGroup(sep string, fn func(*SelectQuery) *SelectQuery) *SelectQuery {
saved := q.prewhere.filters
q.prewhere.filters = nil
q = fn(q)
filters := q.prewhere.filters
q.prewhere.filters = saved
q.prewhere.addGroup(sep, filters)
return q
}
//------------------------------------------------------------------------------
func (q *SelectQuery) Where(query string, args ...any) *SelectQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " AND "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
return q
}
func (q *SelectQuery) WhereOr(query string, args ...any) *SelectQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " OR "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
return q
}
func (q *SelectQuery) WhereGroup(sep string, fn func(*SelectQuery) *SelectQuery) *SelectQuery {
saved := q.where
q.where = nil
saved := q.where.filters
q.where.filters = nil
q = fn(q)
where := q.where
q.where = saved
filters := q.where.filters
q.where.filters = saved
q.addWhereGroup(sep, where)
q.where.addGroup(sep, filters)
return q
}
@ -344,9 +386,19 @@ func (q *SelectQuery) appendQuery(
}
}
b, err = q.appendWhere(fmter, b)
if err != nil {
return nil, err
if len(q.prewhere.filters) > 0 {
b = append(b, " PREWHERE "...)
b, err = appendWhere(fmter, b, q.prewhere.filters)
if err != nil {
return nil, err
}
}
if len(q.where.filters) > 0 {
b = append(b, " WHERE "...)
b, err = appendWhere(fmter, b, q.where.filters)
if err != nil {
return nil, err
}
}
if len(q.group) > 0 {

View File

@ -9,13 +9,14 @@ import (
)
type CreateViewQuery struct {
whereBaseQuery
baseQuery
materialized bool
ifNotExists bool
view chschema.QueryWithArgs
cluster chschema.QueryWithArgs
to chschema.QueryWithArgs
where whereQuery
group []chschema.QueryWithArgs
order chschema.QueryWithArgs
}
@ -24,10 +25,8 @@ var _ Query = (*CreateViewQuery)(nil)
func NewCreateViewQuery(db *DB) *CreateViewQuery {
return &CreateViewQuery{
whereBaseQuery: whereBaseQuery{
baseQuery: baseQuery{
db: db,
},
baseQuery: baseQuery{
db: db,
},
}
}
@ -124,29 +123,31 @@ func (q *CreateViewQuery) IfNotExists() *CreateViewQuery {
//------------------------------------------------------------------------------
func (q *CreateViewQuery) Where(query string, args ...any) *CreateViewQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " AND "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " AND "))
return q
}
func (q *CreateViewQuery) WhereOr(query string, args ...any) *CreateViewQuery {
q.addWhere(chschema.SafeQueryWithSep(query, args, " OR "))
q.where.addFilter(chschema.SafeQueryWithSep(query, args, " OR "))
return q
}
func (q *CreateViewQuery) WhereGroup(sep string, fn func(*CreateViewQuery) *CreateViewQuery) *CreateViewQuery {
saved := q.where
q.where = nil
saved := q.where.filters
q.where.filters = nil
q = fn(q)
where := q.where
q.where = saved
filters := q.where.filters
q.where.filters = saved
q.addWhereGroup(sep, where)
q.where.addGroup(sep, filters)
return q
}
//------------------------------------------------------------------------------
func (q *CreateViewQuery) Group(columns ...string) *CreateViewQuery {
for _, column := range columns {
q.group = append(q.group, chschema.UnsafeIdent(column))
@ -224,9 +225,12 @@ func (q *CreateViewQuery) AppendQuery(fmter chschema.Formatter, b []byte) (_ []b
return nil, err
}
b, err = q.appendWhere(fmter, b)
if err != nil {
return nil, err
if len(q.where.filters) > 0 {
b = append(b, " WHERE "...)
b, err = appendWhere(fmter, b, q.where.filters)
if err != nil {
return nil, err
}
}
if len(q.group) > 0 {