mirror of
https://github.com/ent/ent.git
synced 2026-05-24 09:31:56 +03:00
dialect/sql: support capturing predicates in selectors
This allows custom predicates mutating the root querying and still respect the AND/OR/NOT semantics
This commit is contained in:
committed by
Ariel Mashraki
parent
4787899669
commit
808edd134d
@@ -2146,6 +2146,7 @@ type Selector struct {
|
||||
selection []selection
|
||||
from []TableView
|
||||
joins []join
|
||||
collected [][]*Predicate
|
||||
where *Predicate
|
||||
or bool
|
||||
not bool
|
||||
@@ -2385,8 +2386,35 @@ func (s *Selector) Offset(offset int) *Selector {
|
||||
return s
|
||||
}
|
||||
|
||||
// CollectPredicates indicates the appended predicated should be collected
|
||||
// and not appended to the `WHERE` clause.
|
||||
func (s *Selector) CollectPredicates() *Selector {
|
||||
s.collected = append(s.collected, []*Predicate{})
|
||||
return s
|
||||
}
|
||||
|
||||
// CollectedPredicates returns the collected predicates.
|
||||
func (s *Selector) CollectedPredicates() []*Predicate {
|
||||
if len(s.collected) == 0 {
|
||||
return nil
|
||||
}
|
||||
return s.collected[len(s.collected)-1]
|
||||
}
|
||||
|
||||
// UncollectedPredicates stop collecting predicates.
|
||||
func (s *Selector) UncollectedPredicates() *Selector {
|
||||
if len(s.collected) > 0 {
|
||||
s.collected = s.collected[:len(s.collected)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Where sets or appends the given predicate to the statement.
|
||||
func (s *Selector) Where(p *Predicate) *Selector {
|
||||
if len(s.collected) > 0 {
|
||||
s.collected[len(s.collected)-1] = append(s.collected[len(s.collected)-1], p)
|
||||
return s
|
||||
}
|
||||
if s.not {
|
||||
p = Not(p)
|
||||
s.not = false
|
||||
|
||||
@@ -170,6 +170,63 @@ func FieldContainsFold(name string, substr string) func(*Selector) {
|
||||
}
|
||||
}
|
||||
|
||||
// AndPredicates returns a new predicate for joining multiple generated predicates with AND between them.
|
||||
func AndPredicates[P ~func(*Selector)](predicates ...P) func(*Selector) {
|
||||
return func(s *Selector) {
|
||||
s.CollectPredicates()
|
||||
for _, p := range predicates {
|
||||
p(s)
|
||||
}
|
||||
collected := s.CollectedPredicates()
|
||||
s.UncollectedPredicates()
|
||||
switch len(collected) {
|
||||
case 0:
|
||||
case 1:
|
||||
s.Where(collected[0])
|
||||
default:
|
||||
s.Where(And(collected...))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OrPredicates returns a new predicate for joining multiple generated predicates with OR between them.
|
||||
func OrPredicates[P ~func(*Selector)](predicates ...P) func(*Selector) {
|
||||
return func(s *Selector) {
|
||||
s.CollectPredicates()
|
||||
for _, p := range predicates {
|
||||
p(s)
|
||||
}
|
||||
collected := s.CollectedPredicates()
|
||||
s.UncollectedPredicates()
|
||||
switch len(collected) {
|
||||
case 0:
|
||||
case 1:
|
||||
s.Where(collected[0])
|
||||
default:
|
||||
s.Where(Or(collected...))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NotPredicates wraps the generated predicates with NOT. For example, NOT(P), NOT((P1 AND P2)).
|
||||
func NotPredicates[P ~func(*Selector)](predicates ...P) func(*Selector) {
|
||||
return func(s *Selector) {
|
||||
s.CollectPredicates()
|
||||
for _, p := range predicates {
|
||||
p(s)
|
||||
}
|
||||
collected := s.CollectedPredicates()
|
||||
s.UncollectedPredicates()
|
||||
switch len(collected) {
|
||||
case 0:
|
||||
case 1:
|
||||
s.Where(Not(collected[0]))
|
||||
default:
|
||||
s.Where(Not(And(collected...)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ColumnCheck is a function that verifies whether the
|
||||
// specified column exists within the given table.
|
||||
type ColumnCheck func(table, column string) error
|
||||
|
||||
Reference in New Issue
Block a user