diff --git a/dialect/sql/builder.go b/dialect/sql/builder.go index c1d0155e6..5c43d37fa 100644 --- a/dialect/sql/builder.go +++ b/dialect/sql/builder.go @@ -1061,6 +1061,38 @@ func (p *Predicate) ContainsFold(col, sub string) *Predicate { }) } +func CompositeGT(columns []string, args ...interface{}) *Predicate { + return (&Predicate{}).CompositeGT(columns, args...) +} + +func CompositeLT(columns []string, args ...interface{}) *Predicate { + return (&Predicate{}).CompositeLT(columns, args...) +} + +func (p *Predicate) compositeP(operator string, columns []string, args ...interface{}) *Predicate { + return p.append(func(b *Builder) { + b.Nested(func(nb *Builder) { + nb.IdentComma(columns...) + }) + b.WriteString(operator) + b.WriteString("(") + b.Args(args...) + b.WriteString(")") + }) +} + +// GT returns a composite ">" predicate. +func (p *Predicate) CompositeGT(columns []string, args ...interface{}) *Predicate { + const operator = " > " + return p.compositeP(operator, columns, args...) +} + +// LT appends a composite "<" predicate. +func (p *Predicate) CompositeLT(columns []string, args ...interface{}) *Predicate { + const operator = " < " + return p.compositeP(operator, columns, args...) +} + // Query returns query representation of a predicate. func (p *Predicate) Query() (string, []interface{}) { for _, f := range p.fns { diff --git a/dialect/sql/builder_test.go b/dialect/sql/builder_test.go index 65f69ed19..5725dcc41 100644 --- a/dialect/sql/builder_test.go +++ b/dialect/sql/builder_test.go @@ -1063,6 +1063,50 @@ func TestBuilder(t *testing.T) { wantQuery: `SELECT * FROM "groups" JOIN (SELECT "user_groups"."id" FROM "user_groups" JOIN "users" AS "t0" ON "user_groups"."id" = "t0"."id2" WHERE "t0"."id" = $1) AS "t1" ON "groups"."id" = "t1"."id" LIMIT $2`, wantArgs: []interface{}{"baz", 1}, }, + { + input: func() Querier { + t1 := Table("users") + return Dialect(dialect.Postgres). + Select(). + From(t1). + Where(CompositeGT(t1.Columns("id", "name"), 1, "Ariel")) + }(), + wantQuery: `SELECT * FROM "users" WHERE ("users"."id", "users"."name") > ($1, $2)`, + wantArgs: []interface{}{1, "Ariel"}, + }, + { + input: func() Querier { + t1 := Table("users") + return Dialect(dialect.Postgres). + Select(). + From(t1). + Where(And(EQ("name", "Ariel"), CompositeGT(t1.Columns("id", "name"), 1, "Ariel"))) + }(), + wantQuery: `SELECT * FROM "users" WHERE ("name" = $1) AND (("users"."id", "users"."name") > ($2, $3))`, + wantArgs: []interface{}{"Ariel", 1, "Ariel"}, + }, + { + input: func() Querier { + t1 := Table("users") + return Dialect(dialect.Postgres). + Select(). + From(t1). + Where(And(EQ("name", "Ariel"), Or(EQ("surname", "Doe"), CompositeGT(t1.Columns("id", "name"), 1, "Ariel")))) + }(), + wantQuery: `SELECT * FROM "users" WHERE ("name" = $1) AND ((("surname" = $2) OR (("users"."id", "users"."name") > ($3, $4))))`, + wantArgs: []interface{}{"Ariel", "Doe", 1, "Ariel"}, + }, + { + input: func() Querier { + t1 := Table("users") + return Dialect(dialect.Postgres). + Select(). + From(Table("users")). + Where(And(EQ("name", "Ariel"), CompositeLT(t1.Columns("id", "name"), 1, "Ariel"))) + }(), + wantQuery: `SELECT * FROM "users" WHERE ("name" = $1) AND (("users"."id", "users"."name") < ($2, $3))`, + wantArgs: []interface{}{"Ariel", 1, "Ariel"}, + }, { input: CreateIndex("name_index").Table("users").Column("name"), wantQuery: "CREATE INDEX `name_index` ON `users`(`name`)",