From 736e66fcda1788a59ac1128ca79dce0e0a1bc024 Mon Sep 17 00:00:00 2001 From: nukc <353932158@qq.com> Date: Mon, 5 Nov 2018 03:47:21 +0800 Subject: [PATCH] orm: support filter raw sql --- orm/db_tables.go | 8 +++++++- orm/orm_conds.go | 11 +++++++++++ orm/orm_queryset.go | 9 +++++++++ orm/orm_test.go | 17 +++++++++++++++++ orm/types.go | 5 +++++ 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/orm/db_tables.go b/orm/db_tables.go index 42be5550..4b21a6fc 100644 --- a/orm/db_tables.go +++ b/orm/db_tables.go @@ -372,7 +372,13 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe operator = "exact" } - operSQL, args := t.base.GenerateOperatorSQL(mi, fi, operator, p.args, tz) + var operSQL string + var args []interface{} + if p.isRaw { + operSQL = p.sql + } else { + operSQL, args = t.base.GenerateOperatorSQL(mi, fi, operator, p.args, tz) + } leftCol := fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q) t.base.GenerateOperatorLeftCol(fi, operator, &leftCol) diff --git a/orm/orm_conds.go b/orm/orm_conds.go index f6e389ec..f3fd66f0 100644 --- a/orm/orm_conds.go +++ b/orm/orm_conds.go @@ -31,6 +31,8 @@ type condValue struct { isOr bool isNot bool isCond bool + isRaw bool + sql string } // Condition struct. @@ -45,6 +47,15 @@ func NewCondition() *Condition { return c } +// Raw add raw sql to condition +func (c Condition) Raw(expr string, sql string) *Condition { + if len(sql) == 0 { + panic(fmt.Errorf(" sql cannot empty")) + } + c.params = append(c.params, condValue{exprs: strings.Split(expr, ExprSep), sql: sql, isRaw: true}) + return &c +} + // And add expression to condition func (c Condition) And(expr string, args ...interface{}) *Condition { if expr == "" || len(args) == 0 { diff --git a/orm/orm_queryset.go b/orm/orm_queryset.go index 4bab1d98..b2657c6d 100644 --- a/orm/orm_queryset.go +++ b/orm/orm_queryset.go @@ -79,6 +79,15 @@ func (o querySet) Filter(expr string, args ...interface{}) QuerySeter { return &o } +// add raw sql to querySeter. +func (o querySet) FilterRaw(expr string, sql string) QuerySeter { + if o.cond == nil { + o.cond = NewCondition() + } + o.cond = o.cond.Raw(expr, sql) + return &o +} + // add NOT condition to querySeter. func (o querySet) Exclude(expr string, args ...interface{}) QuerySeter { if o.cond == nil { diff --git a/orm/orm_test.go b/orm/orm_test.go index ceb814ff..89a714b6 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -899,6 +899,18 @@ func TestOperators(t *testing.T) { num, err = qs.Filter("id__between", []int{2, 3}).Count() throwFail(t, err) throwFail(t, AssertIs(num, 2)) + + num, err = qs.FilterRaw("user_name", "= 'slene'").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) + + num, err = qs.FilterRaw("status", "IN (1, 2)").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 2)) + + num, err = qs.FilterRaw("profile_id", "IN (SELECT id FROM user_profile WHERE age=30)").Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 1)) } func TestSetCond(t *testing.T) { @@ -924,6 +936,11 @@ func TestSetCond(t *testing.T) { num, err = qs.SetCond(cond4).Count() throwFail(t, err) throwFail(t, AssertIs(num, 3)) + + cond5 := cond.Raw("user_name", "= 'slene'").OrNotCond(cond.And("user_name", "slene")) + num, err = qs.SetCond(cond5).Count() + throwFail(t, err) + throwFail(t, AssertIs(num, 3)) } func TestLimit(t *testing.T) { diff --git a/orm/types.go b/orm/types.go index 2fdc98c7..8ba4099f 100644 --- a/orm/types.go +++ b/orm/types.go @@ -147,6 +147,11 @@ type QuerySeter interface { // // time compare // qs.Filter("created", time.Now()) Filter(string, ...interface{}) QuerySeter + // add raw sql to querySeter. + // for example: + // qs.FilterRaw("user_id IN (SELECT id FROM profile WHERE age>=18)") + // //sql-> WHERE user_id IN (SELECT id FROM profile WHERE age>=18) + FilterRaw(string, string) QuerySeter // add NOT condition to querySeter. // have the same usage as Filter Exclude(string, ...interface{}) QuerySeter