diff --git a/util/sqlgen/benchmark_test.go b/util/sqlgen/benchmark_test.go index 3cc2e25f2052bf6705902427aaf5cc419cbd3bf6..923950352ff8da46fdd6d2026175fcfb36250149 100644 --- a/util/sqlgen/benchmark_test.go +++ b/util/sqlgen/benchmark_test.go @@ -12,15 +12,21 @@ func BenchmarkColumn(b *testing.B) { } } -func BenchmarkColumnNestedValue(b *testing.B) { +func BenchmarkCompileColumn(b *testing.B) { for i := 0; i < b.N; i++ { - _ = Column{Value: "a"} + _ = Column{Value: "a"}.Compile(defaultTemplate) } } -func BenchmarkCompileColumn(b *testing.B) { +func BenchmarkColumns(b *testing.B) { for i := 0; i < b.N; i++ { - _ = Column{Value: "a"}.Compile(defaultTemplate) + _ = Columns{{"a"}, {"b"}, {"c"}} + } +} + +func BenchmarkCompileColumns(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Columns{{"a"}, {"b"}, {"c"}}.Compile(defaultTemplate) } } @@ -30,6 +36,36 @@ func BenchmarkValue(b *testing.B) { } } +func BenchmarkCompileValue(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Value{"a"}.Compile(defaultTemplate) + } +} + +func BenchmarkValues(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Values{{"a"}, {"b"}, {"c"}, {1}, {2}, {3}} + } +} + +func BenchmarkCompileValues(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Values{{"a"}, {"b"}, {"c"}, {1}, {2}, {3}}.Compile(defaultTemplate) + } +} + +func BenchmarkDatabase(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Database{"TestDatabase"} + } +} + +func BenchmarkCompileDatabase(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Database{"TestDatabase"}.Compile(defaultTemplate) + } +} + func BenchmarkValueRaw(b *testing.B) { for i := 0; i < b.N; i++ { _ = Value{Raw{"a"}} @@ -42,6 +78,76 @@ func BenchmarkColumnValue(b *testing.B) { } } +func BenchmarkCompileColumnValue(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = ColumnValue{Column{"a"}, "=", Value{Raw{"7"}}}.Compile(defaultTemplate) + } +} + +func BenchmarkColumnValues(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = ColumnValues{{Column{"a"}, "=", Value{Raw{"7"}}}} + } +} + +func BenchmarkCompileColumnValues(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = ColumnValues{{Column{"a"}, "=", Value{Raw{"7"}}}}.Compile(defaultTemplate) + } +} + +func BenchmarkOrderBy(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = OrderBy{ + SortColumns: SortColumns{ + SortColumn{Column: Column{"foo"}}, + }, + } + } +} + +func BenchmarkCompileOrderBy(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = OrderBy{ + SortColumns: SortColumns{ + SortColumn{Column: Column{"foo"}}, + }, + }.Compile(defaultTemplate) + } +} + +func BenchmarkGroupBy(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = GroupBy{ + Column{"foo"}, + } + } +} + +func BenchmarkCompileGroupBy(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = GroupBy{ + Column{"foo"}, + }.Compile(defaultTemplate) + } +} + +func BenchmarkWhere(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Where{ + ColumnValue{Column{"baz"}, "=", Value{99}}, + } + } +} + +func BenchmarkCompileWhere(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = Where{ + ColumnValue{Column{"baz"}, "=", Value{99}}, + }.Compile(defaultTemplate) + } +} + func BenchmarkTable(b *testing.B) { for i := 0; i < b.N; i++ { _ = Table{"foo"} @@ -75,14 +181,6 @@ func BenchmarkCompileRandomTable(b *testing.B) { } } -func BenchmarkWhere(b *testing.B) { - for i := 0; i < b.N; i++ { - _ = Where{ - ColumnValue{Column{"a"}, "=", Value{Raw{"7"}}}, - } - } -} - func BenchmarkCompileSelect(b *testing.B) { var stmt Statement diff --git a/util/sqlgen/column.go b/util/sqlgen/column.go index a43ec871888369423acfeefac2530d7974fd67bd..6a69c98de0ec65b3126cbba9d49754f78c5f573d 100644 --- a/util/sqlgen/column.go +++ b/util/sqlgen/column.go @@ -14,20 +14,33 @@ type Column struct { Value interface{} } +func (self Column) Hash() string { + switch t := self.Value.(type) { + case cc: + return `Column(` + t.Hash() + `)` + case string: + return `Column(` + t + `)` + } + return fmt.Sprintf(`Column(%v)`, self.Value) +} + func (self Column) Compile(layout *Template) (compiled string) { - if s, ok := layout.Cache(self); ok { - return s + if c, ok := layout.Read(self); ok { + return c } switch value := self.Value.(type) { case string: - input := strings.TrimSpace(value) + // input := strings.TrimSpace(value) + input := trimString(value) - chunks := reAliasSeparator.Split(input, 2) + //chunks := reAliasSeparator.Split(input, 2) + chunks := separateByAS(input) if len(chunks) == 1 { - chunks = reSpaceSeparator.Split(input, 2) + //chunks = reSpaceSeparator.Split(input, 2) + chunks = separateBySpace(input) } name := chunks[0] @@ -35,7 +48,8 @@ func (self Column) Compile(layout *Template) (compiled string) { nameChunks := strings.SplitN(name, layout.ColumnSeparator, 2) for i := range nameChunks { - nameChunks[i] = strings.TrimSpace(nameChunks[i]) + // nameChunks[i] = strings.TrimSpace(nameChunks[i]) + nameChunks[i] = trimString(nameChunks[i]) nameChunks[i] = mustParse(layout.IdentifierQuote, Raw{nameChunks[i]}) } @@ -44,7 +58,8 @@ func (self Column) Compile(layout *Template) (compiled string) { var alias string if len(chunks) > 1 { - alias = strings.TrimSpace(chunks[1]) + // alias = strings.TrimSpace(chunks[1]) + alias = trimString(chunks[1]) alias = mustParse(layout.IdentifierQuote, Raw{alias}) } @@ -55,7 +70,7 @@ func (self Column) Compile(layout *Template) (compiled string) { compiled = fmt.Sprintf("%v", self.Value) } - layout.SetCache(self, compiled) + layout.Write(self, compiled) - return compiled + return } diff --git a/util/sqlgen/column_value.go b/util/sqlgen/column_value.go index 2d8dfd1577b94e3ceb84ff30e978bf52c24adea5..fbe57987c43aec83b0ed24b42cb15156dd82c3f9 100644 --- a/util/sqlgen/column_value.go +++ b/util/sqlgen/column_value.go @@ -16,10 +16,14 @@ type columnValue_s struct { Value string } +func (self ColumnValue) Hash() string { + return `ColumnValue(` + self.Column.Hash() + `;` + self.Operator + `;` + self.Value.Hash() + `)` +} + func (self ColumnValue) Compile(layout *Template) (compiled string) { - if s, ok := layout.Cache(self); ok { - return s + if c, ok := layout.Read(self); ok { + return c } data := columnValue_s{ @@ -30,18 +34,26 @@ func (self ColumnValue) Compile(layout *Template) (compiled string) { compiled = mustParse(layout.ColumnValue, data) + layout.Write(self, compiled) + return } type ColumnValues []ColumnValue +func (self ColumnValues) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `ColumnValues(` + strings.Join(hash, `,`) + `)` +} + func (self ColumnValues) Compile(layout *Template) (compiled string) { - /* - if s, ok := layout.Cache(self); ok { - return s - } - */ + if c, ok := layout.Read(self); ok { + return c + } l := len(self) @@ -53,5 +65,7 @@ func (self ColumnValues) Compile(layout *Template) (compiled string) { compiled = strings.Join(out, layout.IdentifierSeparator) + layout.Write(self, compiled) + return } diff --git a/util/sqlgen/columns.go b/util/sqlgen/columns.go index 0cf1039306d5f61bd036cd4a94698c24dc5fff22..dfe41f2e38c5133550751bd4d1a3501081e1537c 100644 --- a/util/sqlgen/columns.go +++ b/util/sqlgen/columns.go @@ -6,7 +6,20 @@ import ( type Columns []Column -func (self Columns) Compile(layout *Template) string { +func (self Columns) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `Columns(` + strings.Join(hash, `,`) + `)` +} + +func (self Columns) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + l := len(self) if l > 0 { @@ -16,7 +29,10 @@ func (self Columns) Compile(layout *Template) string { out[i] = self[i].Compile(layout) } - return strings.Join(out, layout.IdentifierSeparator) + compiled = strings.Join(out, layout.IdentifierSeparator) } - return "" + + layout.Write(self, compiled) + + return } diff --git a/util/sqlgen/database.go b/util/sqlgen/database.go index 4e89db551a3f3ee6c04ddfc26238858c75db8053..6c5f731477d0053b264ff9640f03a2288c1e8dbd 100644 --- a/util/sqlgen/database.go +++ b/util/sqlgen/database.go @@ -8,6 +8,18 @@ type Database struct { Value string } -func (self Database) Compile(layout *Template) string { - return mustParse(layout.IdentifierQuote, Raw{fmt.Sprintf(`%v`, self.Value)}) +func (self Database) Hash() string { + return `Database(` + self.Value + `)` +} + +func (self Database) Compile(layout *Template) (compiled string) { + if c, ok := layout.Read(self); ok { + return c + } + + compiled = mustParse(layout.IdentifierQuote, Raw{fmt.Sprintf(`%v`, self.Value)}) + + layout.Write(self, compiled) + + return } diff --git a/util/sqlgen/default.go b/util/sqlgen/default.go index 9038db0fa9cd0eb9097c815ebc7f26edee4391f8..4b2a3f20922f845b401e3af2416e891b2da8a57b 100644 --- a/util/sqlgen/default.go +++ b/util/sqlgen/default.go @@ -1,5 +1,9 @@ package sqlgen +import ( + "upper.io/cache" +) + const ( defaultColumnSeparator = `.` defaultIdentifierSeparator = `, ` @@ -113,34 +117,33 @@ const ( ) var defaultTemplate = &Template{ - defaultColumnSeparator, - defaultIdentifierSeparator, - defaultIdentifierQuote, - defaultValueSeparator, - defaultValueQuote, - defaultAndKeyword, - defaultOrKeyword, - defaultNotKeyword, - defaultDescKeyword, - defaultAscKeyword, - defaultDefaultOperator, - defaultClauseGroup, - defaultClauseOperator, - defaultColumnValue, - defaultTableAliasLayout, - defaultColumnAliasLayout, - defaultSortByColumnLayout, - defaultWhereLayout, - defaultOrderByLayout, - defaultInsertLayout, - defaultSelectLayout, - defaultUpdateLayout, - defaultDeleteLayout, - defaultTruncateLayout, - defaultDropDatabaseLayout, - defaultDropTableLayout, - defaultSelectCountLayout, - defaultGroupByLayout, - nil, - nil, + ColumnSeparator: defaultColumnSeparator, + IdentifierSeparator: defaultIdentifierSeparator, + IdentifierQuote: defaultIdentifierQuote, + ValueSeparator: defaultValueSeparator, + ValueQuote: defaultValueQuote, + AndKeyword: defaultAndKeyword, + OrKeyword: defaultOrKeyword, + NotKeyword: defaultNotKeyword, + DescKeyword: defaultDescKeyword, + AscKeyword: defaultAscKeyword, + DefaultOperator: defaultDefaultOperator, + ClauseGroup: defaultClauseGroup, + ClauseOperator: defaultClauseOperator, + ColumnValue: defaultColumnValue, + TableAliasLayout: defaultTableAliasLayout, + ColumnAliasLayout: defaultColumnAliasLayout, + SortByColumnLayout: defaultSortByColumnLayout, + WhereLayout: defaultWhereLayout, + OrderByLayout: defaultOrderByLayout, + InsertLayout: defaultInsertLayout, + SelectLayout: defaultSelectLayout, + UpdateLayout: defaultUpdateLayout, + DeleteLayout: defaultDeleteLayout, + TruncateLayout: defaultTruncateLayout, + DropDatabaseLayout: defaultDropDatabaseLayout, + DropTableLayout: defaultDropTableLayout, + SelectCountLayout: defaultSelectCountLayout, + GroupByLayout: defaultGroupByLayout, + Cache: cache.NewCache(), } diff --git a/util/sqlgen/group_by.go b/util/sqlgen/group_by.go index 54e7f03ffd9ec0b3baf47ff82425663b618e5673..28aa812fce9d25ace9f726c627530568aa83a9a2 100644 --- a/util/sqlgen/group_by.go +++ b/util/sqlgen/group_by.go @@ -6,14 +6,26 @@ type groupBy_s struct { GroupColumns string } -func (self GroupBy) Compile(layout *Template) string { +func (self GroupBy) Hash() string { + return `GroupBy(` + Columns(self).Hash() + `)` +} + +func (self GroupBy) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + if len(self) > 0 { data := groupBy_s{ GroupColumns: Columns(self).Compile(layout), } - return mustParse(layout.GroupByLayout, data) + compiled = mustParse(layout.GroupByLayout, data) } - return "" + + layout.Write(self, compiled) + + return } diff --git a/util/sqlgen/interfaces.go b/util/sqlgen/interfaces.go new file mode 100644 index 0000000000000000000000000000000000000000..234742c40098cf1696bbe100b25faafa6070482a --- /dev/null +++ b/util/sqlgen/interfaces.go @@ -0,0 +1,14 @@ +package sqlgen + +import ( + "upper.io/cache" +) + +type cc interface { + cache.Cacheable + compilable +} + +type compilable interface { + Compile(*Template) string +} diff --git a/util/sqlgen/order_by.go b/util/sqlgen/order_by.go index 758a13eb3bf25ee00a071f8102d651527348d6e7..a88fe69a3cb5e7077ece8af0e4f49d94d1b5c86a 100644 --- a/util/sqlgen/order_by.go +++ b/util/sqlgen/order_by.go @@ -1,6 +1,8 @@ package sqlgen -import "strings" +import ( + "strings" +) type SortColumn struct { Column @@ -14,6 +16,18 @@ type sortColumn_s struct { type SortColumns []SortColumn +func (self SortColumn) Hash() string { + return `SortColumn(` + self.Column.Hash() + `;` + self.Sort.Hash() + `)` +} + +func (self SortColumns) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `SortColumns(` + strings.Join(hash, `,`) + `)` +} + func (self SortColumns) Compile(layout *Template) string { l := len(self) s := make([]string, 0, l) @@ -23,12 +37,21 @@ func (self SortColumns) Compile(layout *Template) string { return strings.Join(s, layout.IdentifierSeparator) } -func (self SortColumn) Compile(layout *Template) string { +func (self SortColumn) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + data := sortColumn_s{ Column: self.Column.Compile(layout), Sort: self.Sort.Compile(layout), } - return mustParse(layout.SortByColumnLayout, data) + + compiled = mustParse(layout.SortByColumnLayout, data) + + layout.Write(self, compiled) + return } type OrderBy struct { @@ -39,14 +62,26 @@ type orderBy_s struct { SortColumns string } -func (self OrderBy) Compile(layout *Template) string { +func (self OrderBy) Hash() string { + return `OrderBy(` + self.SortColumns.Hash() + `)` +} + +func (self OrderBy) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + if len(self.SortColumns) > 0 { data := orderBy_s{ SortColumns: self.SortColumns.Compile(layout), } - return mustParse(layout.OrderByLayout, data) + compiled = mustParse(layout.OrderByLayout, data) } - return "" + + layout.Write(self, compiled) + + return } type Sort uint8 @@ -57,6 +92,16 @@ const ( SqlSortDesc ) +func (self Sort) Hash() string { + switch self { + case SqlSortAsc: + return `Sort(1)` + case SqlSortDesc: + return `Sort(2)` + } + return `Sort(0)` +} + func (self Sort) Compile(layout *Template) string { switch self { case SqlSortAsc: diff --git a/util/sqlgen/raw.go b/util/sqlgen/raw.go index d62a3aca8fbdbe1eebfdf9613c18eb0afbb5d177..cda0e66bd25c0805badfdf648b7f5b7ab6481fcf 100644 --- a/util/sqlgen/raw.go +++ b/util/sqlgen/raw.go @@ -4,6 +4,14 @@ type Raw struct { Raw string } +func (self Raw) Hash() string { + return `Raw(` + self.Raw + `)` +} + +func (self Raw) Compile(*Template) string { + return self.Raw +} + func (self Raw) String() string { return self.Raw } diff --git a/util/sqlgen/table.go b/util/sqlgen/table.go index 141c4dc2052c2b34d0b369b9077c41f419edba02..ed28c8b596327a0b6712d9e2fe6d0c0bc28205cd 100644 --- a/util/sqlgen/table.go +++ b/util/sqlgen/table.go @@ -1,16 +1,9 @@ package sqlgen import ( - "regexp" "strings" ) -var ( - reTableSeparator = regexp.MustCompile(`\s*?,\s*?`) - reAliasSeparator = regexp.MustCompile(`(?i:\s+AS\s+)`) - reSpaceSeparator = regexp.MustCompile(`\s+`) -) - type table_t struct { Name string Alias string @@ -55,7 +48,7 @@ func quotedTableName(layout *Template, input string) string { } func (self Table) Hash() string { - return self.Name + return `Table(` + self.Name + `)` } func (self Table) Compile(layout *Template) (compiled string) { @@ -64,25 +57,22 @@ func (self Table) Compile(layout *Template) (compiled string) { return } - if layout.isCached(self) { - - compiled = layout.getCache(self) - - } else { + if c, ok := layout.Read(self); ok { + return c + } - // Splitting tables by a comma - parts := separateByComma(self.Name) + // Splitting tables by a comma + parts := separateByComma(self.Name) - l := len(parts) + l := len(parts) - for i := 0; i < l; i++ { - parts[i] = quotedTableName(layout, parts[i]) - } + for i := 0; i < l; i++ { + parts[i] = quotedTableName(layout, parts[i]) + } - compiled = strings.Join(parts, layout.IdentifierSeparator) + compiled = strings.Join(parts, layout.IdentifierSeparator) - layout.setCache(self, compiled) - } + layout.Write(self, compiled) return } diff --git a/util/sqlgen/template.go b/util/sqlgen/template.go index 7502e27f73b0b80bf92916d98d4241ceac3d31c4..e3ff175cb0619793fe32f907581eb7de2e687104 100644 --- a/util/sqlgen/template.go +++ b/util/sqlgen/template.go @@ -1,5 +1,9 @@ package sqlgen +import ( + "upper.io/cache" +) + type Template struct { ColumnSeparator string IdentifierSeparator string @@ -29,50 +33,5 @@ type Template struct { DropTableLayout string SelectCountLayout string GroupByLayout string - cache map[interface{}]string - cachedTemplates map[string]string -} - -type cacheable interface { - Hash() string -} - -func (self *Template) SetCache(key interface{}, value string) { - if self.cache == nil { - self.cache = make(map[interface{}]string) - } - self.cache[key] = value -} - -func (self *Template) Cache(key interface{}) (string, bool) { - if self.cache != nil { - if s, ok := self.cache[key]; ok { - return s, true - } - } - return "", false -} - -func (self *Template) getCache(i cacheable) string { - if self.cachedTemplates == nil { - return "" - } - return self.cachedTemplates[i.Hash()] -} - -func (self *Template) setCache(i cacheable, s string) { - if self.cachedTemplates == nil { - self.cachedTemplates = map[string]string{} - } - self.cachedTemplates[i.Hash()] = s -} - -func (self *Template) isCached(i cacheable) bool { - if self.cachedTemplates == nil { - return false - } - if _, ok := self.cachedTemplates[i.Hash()]; ok { - return true - } - return false + *cache.Cache } diff --git a/util/sqlgen/value.go b/util/sqlgen/value.go index 651c809364673e689b289c13c56e71b0b8998c5a..aae5f25efa97785090a2870cadd486a1d4bb5f86 100644 --- a/util/sqlgen/value.go +++ b/util/sqlgen/value.go @@ -11,14 +11,47 @@ type Value struct { Value interface{} } -func (self Value) Compile(layout *Template) string { +func (self Value) Hash() string { + switch t := self.Value.(type) { + case cc: + return `Value(` + t.Hash() + `)` + case string: + return `Value(` + t + `)` + } + return fmt.Sprintf(`Value(%v)`, self.Value) +} + +func (self Value) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + if raw, ok := self.Value.(Raw); ok { - return raw.Raw + compiled = raw.Raw + } else { + compiled = mustParse(layout.ValueQuote, Raw{fmt.Sprintf(`%v`, self.Value)}) } - return mustParse(layout.ValueQuote, Raw{fmt.Sprintf(`%v`, self.Value)}) + + layout.Write(self, compiled) + + return } -func (self Values) Compile(layout *Template) string { +func (self Values) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `Values(` + strings.Join(hash, `,`) + `)` +} + +func (self Values) Compile(layout *Template) (compiled string) { + + if c, ok := layout.Read(self); ok { + return c + } + l := len(self) if l > 0 { @@ -28,8 +61,10 @@ func (self Values) Compile(layout *Template) string { chunks = append(chunks, self[i].Compile(layout)) } - return strings.Join(chunks, layout.ValueSeparator) + compiled = strings.Join(chunks, layout.ValueSeparator) } - return "" + layout.Write(self, compiled) + + return } diff --git a/util/sqlgen/where.go b/util/sqlgen/where.go index df61fcf33919db5550f76e5c79d1955be93ed59b..bcc9b677649258ac887fea097f5cab3b8f3eb3d3 100644 --- a/util/sqlgen/where.go +++ b/util/sqlgen/where.go @@ -5,49 +5,87 @@ import ( ) type ( - Or []interface{} - And []interface{} - Where []interface{} + Or []cc + And []cc + Where []cc ) type conds struct { Conds string } -func (self Or) Compile(layout *Template) string { - return groupCondition(layout, self, mustParse(layout.ClauseOperator, layout.OrKeyword)) +func (self Or) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `Or(` + strings.Join(hash, `,`) + `)` +} + +func (self Or) Compile(layout *Template) (compiled string) { + if c, ok := layout.Read(self); ok { + return c + } + + compiled = groupCondition(layout, self, mustParse(layout.ClauseOperator, layout.OrKeyword)) + + layout.Write(self, compiled) + + return } -func (self And) Compile(layout *Template) string { - return groupCondition(layout, self, mustParse(layout.ClauseOperator, layout.AndKeyword)) +func (self And) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `And(` + strings.Join(hash, `,`) + `)` } -func (self Where) Compile(layout *Template) string { +func (self And) Compile(layout *Template) (compiled string) { + if c, ok := layout.Read(self); ok { + return c + } + + compiled = groupCondition(layout, self, mustParse(layout.ClauseOperator, layout.AndKeyword)) + + layout.Write(self, compiled) + + return +} + +func (self Where) Hash() string { + hash := make([]string, 0, len(self)) + for i := range self { + hash = append(hash, self[i].Hash()) + } + return `Where(` + strings.Join(hash, `,`) + `)` +} + +func (self Where) Compile(layout *Template) (compiled string) { + if c, ok := layout.Read(self); ok { + return c + } + grouped := groupCondition(layout, self, mustParse(layout.ClauseOperator, layout.AndKeyword)) + if grouped != "" { - return mustParse(layout.WhereLayout, conds{grouped}) + compiled = mustParse(layout.WhereLayout, conds{grouped}) } - return "" + + layout.Write(self, compiled) + + return } -func groupCondition(layout *Template, terms []interface{}, joinKeyword string) string { +func groupCondition(layout *Template, terms []cc, joinKeyword string) string { l := len(terms) chunks := make([]string, 0, l) if l > 0 { - var i int - for i = 0; i < l; i++ { - switch v := terms[i].(type) { - case ColumnValue: - chunks = append(chunks, v.Compile(layout)) - case Or: - chunks = append(chunks, v.Compile(layout)) - case And: - chunks = append(chunks, v.Compile(layout)) - case Raw: - chunks = append(chunks, v.String()) - } + for i := 0; i < l; i++ { + chunks = append(chunks, terms[i].Compile(layout)) } }