diff --git a/builder_x.go b/builder_x.go index 0ec4eac..c09a7fd 100644 --- a/builder_x.go +++ b/builder_x.go @@ -79,6 +79,9 @@ func (x *BuilderX) ResultKeys(resultKeys ...string) *BuilderX { } func (x *BuilderX) Source(po Po) *BuilderX { + if len(x.sxs) == 0 { + x.sxs = append(x.sxs, new(SourceX)) + } x.sxs[0].po = po return x } @@ -117,28 +120,41 @@ func (x *BuilderX) Agg(fn string, vs ...interface{}) *BuilderX { return x } -func (builder *BuilderX) Build() *Built { - if builder == nil { +func (x *BuilderX) Build() *Built { + if x == nil { panic("sqlxb.Builder is nil") } - builder.optimizeSourceBuilder() + x.optimizeSourceBuilder() built := Built{ - ResultKeys: builder.resultKeys, - ConditionX: builder.bbs, - Sorts: builder.sorts, - Aggs: builder.aggs, - Havings: builder.havings, - GroupBys: builder.groupBys, - OrSourceSql: builder.orSourceSql, - Sbs: builder.sxs, - Svs: builder.svs, - - Po: builder.po, + ResultKeys: x.resultKeys, + ConditionX: x.bbs, + Sorts: x.sorts, + Aggs: x.aggs, + Havings: x.havings, + GroupBys: x.groupBys, + OrSourceSql: x.orSourceSql, + Sbs: x.sxs, + Svs: x.svs, + + Po: x.po, } - if builder.pageBuilder != nil { - built.PageCondition = &builder.pageBuilder.condition + if x.pageBuilder != nil { + built.PageCondition = &x.pageBuilder.condition } return &built } + +func (x *BuilderX) Sub(s string, sub func(sub *BuilderX)) *BuilderX { + + b := new(BuilderX) + sub(b) + bb := Bb{ + op: SUB, + key: s, + value: b, + } + x.bbs = append(x.bbs, bb) + return x +} diff --git a/oper.go b/oper.go index 865599f..824d9ec 100644 --- a/oper.go +++ b/oper.go @@ -7,7 +7,7 @@ // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -19,6 +19,7 @@ package sqlxb const ( X = "" AGG = "" + SUB = "SUB" AND = "AND" OR = "OR" AND_SUB = AND diff --git a/source_builder_optimization.go b/source_builder_optimization.go index eba84ea..5f96576 100644 --- a/source_builder_optimization.go +++ b/source_builder_optimization.go @@ -20,20 +20,20 @@ import ( "strings" ) -func (builder *BuilderX) WithoutOptimization() *BuilderX { - builder.isWithoutOptimization = true - return builder +func (x *BuilderX) WithoutOptimization() *BuilderX { + x.isWithoutOptimization = true + return x } -func (builder *BuilderX) optimizeSourceBuilder() { - if builder.isWithoutOptimization { +func (x *BuilderX) optimizeSourceBuilder() { + if x.isWithoutOptimization { return } - if len(builder.resultKeys) == 0 || len(builder.sxs) < 2 { + if len(x.resultKeys) == 0 || len(x.sxs) < 2 { return } - builder.removeSourceBuilder(builder.sxs, func(useds *[]*SourceX, ele *SourceX, i int) bool { + x.removeSourceBuilder(x.sxs, func(useds *[]*SourceX, ele *SourceX, i int) bool { if ele.sub != nil && (ele.join != nil && !strings.Contains(ele.join.join, "LEFT")) { return false @@ -44,7 +44,7 @@ func (builder *BuilderX) optimizeSourceBuilder() { return false } } - for _, v := range *builder.conds() { + for _, v := range *x.conds() { if ele.po != nil && strings.Contains(v, ele.po.TableName()+".") { //has return or condition return false } @@ -54,8 +54,8 @@ func (builder *BuilderX) optimizeSourceBuilder() { } //target - for j := len(builder.sxs) - 1; j > i; j-- { - var sb = builder.sxs[j] + for j := len(x.sxs) - 1; j > i; j-- { + var sb = x.sxs[j] if sb.join != nil && sb.join.on != nil && sb.join.on.bbs != nil { for _, bb := range sb.join.on.bbs { @@ -74,13 +74,13 @@ func (builder *BuilderX) optimizeSourceBuilder() { }) } -func (builder *BuilderX) conds() *[]string { +func (x *BuilderX) conds() *[]string { condArr := []string{} - for _, v := range builder.resultKeys { + for _, v := range x.resultKeys { condArr = append(condArr, v) } - bbps := builder.CondBuilder.bbs + bbps := x.CondBuilder.bbs if bbps != nil { for _, v := range bbps { @@ -88,8 +88,8 @@ func (builder *BuilderX) conds() *[]string { } } - if len(builder.sxs) > 0 { - for _, sb := range builder.sxs { + if len(x.sxs) > 0 { + for _, sb := range x.sxs { if sb.join != nil && sb.join.on != nil && sb.join.on.bbs != nil { for i, bb := range sb.join.on.bbs { if i > 0 { @@ -102,7 +102,7 @@ func (builder *BuilderX) conds() *[]string { return &condArr } -func (builder *BuilderX) removeSourceBuilder(sbs []*SourceX, canRemove canRemove) { +func (x *BuilderX) removeSourceBuilder(sbs []*SourceX, canRemove canRemove) { useds := []*SourceX{} j := 0 leng := len(sbs) @@ -119,10 +119,10 @@ func (builder *BuilderX) removeSourceBuilder(sbs []*SourceX, canRemove canRemove j = 0 if length < leng { for i := length - 1; i > -1; i-- { //reverse - (builder.sxs)[j] = useds[i] + (x.sxs)[j] = useds[i] j++ } - builder.sxs = (builder.sxs)[:j] + x.sxs = (x.sxs)[:j] } } diff --git a/to_result_key.go b/to_result_key.go index 709c5cf..53ea378 100644 --- a/to_result_key.go +++ b/to_result_key.go @@ -7,7 +7,7 @@ // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -57,7 +57,7 @@ func buildResultKey(key string, km map[string]string) string { return key } -func (built *Built) toResultKeyScript(bp *strings.Builder, km map[string]string) { +func (built *Built) toResultKeySql(bp *strings.Builder, km map[string]string) { bp.WriteString(SELECT) if built.ResultKeys == nil { bp.WriteString(STAR) @@ -80,7 +80,7 @@ func (built *Built) toResultKeyScript(bp *strings.Builder, km map[string]string) } } -func (built *Built) toResultKeyScriptOfCount(bpCount *strings.Builder) { +func (built *Built) toResultKeySqlOfCount(bpCount *strings.Builder) { if built.ResultKeys != nil && len(built.ResultKeys) > 0 { bpCount.WriteString(COUNT_KEY_SCRIPT_LEFT) bpCount.WriteString(built.ResultKeys[0]) diff --git a/to_source_script_by_builder.go b/to_source_sql_by_builder.go similarity index 89% rename from to_source_script_by_builder.go rename to to_source_sql_by_builder.go index d9a7f43..bcbf9f2 100644 --- a/to_source_script_by_builder.go +++ b/to_source_sql_by_builder.go @@ -21,7 +21,7 @@ import ( "strings" ) -func (built *Built) toSourceScriptBySql(bp *strings.Builder) bool { +func (built *Built) toSourceSqlBySql(bp *strings.Builder) bool { if (len(built.Sbs) == 1) && (built.OrSourceSql != "") { var sql = strings.Trim(built.OrSourceSql, SPACE) if strings.HasPrefix(sql, "FROM") { @@ -33,7 +33,7 @@ func (built *Built) toSourceScriptBySql(bp *strings.Builder) bool { return false } -func (built *Built) toSourceScriptByBuilder(vs *[]interface{}, sb *SourceX, bp *strings.Builder) { +func (built *Built) toSourceSqlByBuilder(vs *[]interface{}, sb *SourceX, bp *strings.Builder) { if sb.join != nil { //JOIN bp.WriteString(SPACE) bp.WriteString(sb.join.join) @@ -62,7 +62,7 @@ func (built *Built) toSourceScriptByBuilder(vs *[]interface{}, sb *SourceX, bp * bp.WriteString(sb.s) } else { bp.WriteString(ON_SCRIPT) - built.toConditionScript(sb.join.on.bbs, bp, vs, nil) + built.toConditionSql(sb.join.on.bbs, bp, vs, nil) } } } diff --git a/to_sql.go b/to_sql.go index f62ede3..4047d12 100644 --- a/to_sql.go +++ b/to_sql.go @@ -39,27 +39,27 @@ type Built struct { Po Po } -func (built *Built) toSourceScriptOfCount(bpCount *strings.Builder) { - built.toSourceScript(nil, bpCount) +func (built *Built) toSourceSqlOfCount(bpCount *strings.Builder) { + built.toSourceSql(nil, bpCount) } -func (built *Built) toConditionScriptOfCount(bbs []Bb, bpCount *strings.Builder) { - built.toConditionScript(bbs, bpCount, nil, nil) +func (built *Built) toConditionSqlOfCount(bbs []Bb, bpCount *strings.Builder) { + built.toConditionSql(bbs, bpCount, nil, nil) } func (built *Built) toGroupBySqlOfCount(bpCount *strings.Builder) { built.toGroupBySql(bpCount) } -func (built *Built) toSourceScript(vs *[]interface{}, bp *strings.Builder) { +func (built *Built) toSourceSql(vs *[]interface{}, bp *strings.Builder) { if built.Po == nil { - if built.toSourceScriptBySql(bp) { + if built.toSourceSqlBySql(bp) { return } for _, sb := range built.Sbs { - built.toSourceScriptByBuilder(vs, sb, bp) + built.toSourceSqlByBuilder(vs, sb, bp) } } else { bp.WriteString(built.Po.TableName()) @@ -101,8 +101,23 @@ func (built *Built) toBb(bb Bb, bp *strings.Builder, vs *[]interface{}) { return } bp.WriteString(BEGIN_SUB) - built.toConditionScript(bb.subs, bp, vs, nil) + built.toConditionSql(bb.subs, bp, vs, nil) bp.WriteString(END_SUB) + case SUB: + var bx = *bb.value.(*BuilderX) + ss, _ := bx.Build().sqlData(vs, nil) + ss = BEGIN_SUB + ss + END_SUB + if bb.key != "" { + if strings.Contains(bb.key, PLACE_HOLDER) { + bp.WriteString(strings.ReplaceAll(bb.key, PLACE_HOLDER, ss)) + } else { + bp.WriteString(bb.key) + bp.WriteString(SPACE) + bp.WriteString(ss) + } + } else { + bp.WriteString(ss) + } default: bp.WriteString(bb.key) bp.WriteString(SPACE) @@ -114,7 +129,7 @@ func (built *Built) toBb(bb Bb, bp *strings.Builder, vs *[]interface{}) { } } -func (built *Built) toConditionScript(bbs []Bb, bp *strings.Builder, vs *[]interface{}, filterLast func() *Bb) { +func (built *Built) toConditionSql(bbs []Bb, bp *strings.Builder, vs *[]interface{}, filterLast func() *Bb) { length := len(bbs) @@ -179,7 +194,7 @@ func (built *Built) toHavingSql(vs *[]interface{}, bp *strings.Builder) { return } bp.WriteString(HAVING) - built.toConditionScript(built.Havings, bp, vs, nil) + built.toConditionSql(built.Havings, bp, vs, nil) } func (built *Built) toHavingSqlOfCount(bp *strings.Builder) { @@ -241,7 +256,7 @@ func (built *Built) countBuilder() *strings.Builder { func (built *Built) SqlOfCondition() ([]interface{}, string) { vs := []interface{}{} sb := strings.Builder{} - built.toConditionScript(built.ConditionX, &sb, &vs, built.filterLast) + built.toConditionSql(built.ConditionX, &sb, &vs, built.filterLast) conditionSql := sb.String() return vs, conditionSql } @@ -284,11 +299,11 @@ func (built *Built) Sql() ([]interface{}, string, string, map[string]string) { func (built *Built) sqlData(vs *[]interface{}, km map[string]string) (string, map[string]string) { sb := strings.Builder{} - built.toResultKeyScript(&sb, km) + built.toResultKeySql(&sb, km) built.sqlFrom(&sb) - built.toSourceScript(vs, &sb) + built.toSourceSql(vs, &sb) built.sqlWhere(&sb) - built.toConditionScript(built.ConditionX, &sb, vs, built.filterLast) + built.toConditionSql(built.ConditionX, &sb, vs, built.filterLast) built.toAggSql(vs, &sb) built.toGroupBySql(&sb) built.toHavingSql(vs, &sb) @@ -303,11 +318,11 @@ func (built *Built) sqlCount() string { if sbCount == nil { return "" } - built.toResultKeyScriptOfCount(sbCount) + built.toResultKeySqlOfCount(sbCount) built.countSqlFrom(sbCount) - built.toSourceScriptOfCount(sbCount) + built.toSourceSqlOfCount(sbCount) built.countSqlWhere(sbCount) - built.toConditionScriptOfCount(built.ConditionX, sbCount) + built.toConditionSqlOfCount(built.ConditionX, sbCount) built.toAggSqlOfCount(sbCount) built.toGroupBySqlOfCount(sbCount) built.toHavingSqlOfCount(sbCount)