package db import ( "gorm.io/gorm" "gorm.io/gorm/clause" ) type Expr struct { clauses []clause.Expression } func (e *Expr) add(expr clause.Expression) *Expr { e.clauses = append(e.clauses, expr) return e } func (e *Expr) Eq(col string, val any) *Expr { return e.add(clause.Eq{Column: col, Value: val}) } func (e *Expr) Neq(col string, val any) *Expr { return e.add(clause.Neq{Column: col, Value: val}) } func (e *Expr) Lt(col string, val any) *Expr { return e.add(clause.Lt{Column: col, Value: val}) } func (e *Expr) Lte(col string, val any) *Expr { return e.add(clause.Lte{Column: col, Value: val}) } func (e *Expr) Gt(col string, val any) *Expr { return e.add(clause.Gt{Column: col, Value: val}) } func (e *Expr) Gte(col string, val any) *Expr { return e.add(clause.Gte{Column: col, Value: val}) } func (e *Expr) Between(col string, less, more any) *Expr { return e.add(between{col, less, more}) } func (e *Expr) NotBetween(col string, less, more any) *Expr { return e.add(clause.Not(between{col, less, more})) } func (e *Expr) IsNull(col string) *Expr { return e.add(null{col}) } func (e *Expr) NotNull(col string) *Expr { return e.add(clause.Not(null{col})) } func (e *Expr) Like(col, tpl string) *Expr { return e.add(clause.Like{Column: col, Value: tpl}) } func (e *Expr) NotLike(col, tpl string) *Expr { return e.add(clause.Not(clause.Like{Column: col, Value: tpl})) } func (e *Expr) In(col string, values ...any) *Expr { return e.add(clause.IN{Column: col, Values: values}) } func (e *Expr) NotIn(col string, values ...any) *Expr { return e.add(clause.Not(clause.IN{Column: col, Values: values})) } func (e *Expr) When(condition bool, then func(ex *Expr), elses ...func(ex *Expr)) *Expr { if condition { then(e) } else { for _, els := range elses { els(e) } } return e } func (e *Expr) Or(or func(ex *Expr)) *Expr { other := &Expr{} or(other) if len(other.clauses) == 0 { return e } if len(e.clauses) == 0 { e.clauses = other.clauses[:] return e } e.clauses = []clause.Expression{ clause.Or( clause.And(e.clauses...), clause.And(other.clauses...), ), } return e } func (e *Expr) And(and func(ex *Expr)) *Expr { other := &Expr{} and(other) if len(other.clauses) == 0 { return e } if len(e.clauses) == 0 { e.clauses = other.clauses[:] return e } e.clauses = []clause.Expression{ clause.And( clause.And(e.clauses...), clause.And(other.clauses...), ), } return e } func (e *Expr) Not(not func(ex *Expr)) *Expr { other := &Expr{} not(other) if len(other.clauses) == 0 { return e } return e.add(clause.Not(other.clauses...)) } func (e *Expr) Scopes(tx *gorm.DB) *gorm.DB { if e.clauses != nil { for _, express := range e.clauses { tx = tx.Where(express) } } return tx } type null struct { Column any } func (n null) Build(builder clause.Builder) { builder.WriteQuoted(n.Column) builder.WriteString(" IS NULL") } func (n null) NegationBuild(builder clause.Builder) { builder.WriteQuoted(n.Column) builder.WriteString(" IS NOT NULL") } type between struct { Column any Less any More any } func (b between) Build(builder clause.Builder) { b.build(builder, " BETWEEN ") } func (b between) NegationBuild(builder clause.Builder) { b.build(builder, " NOT BETWEEN ") } func (b between) build(builder clause.Builder, op string) { builder.WriteQuoted(b.Column) builder.WriteString(op) builder.AddVar(builder, b.Less) builder.WriteString(" And ") builder.AddVar(builder, b.More) }