1// Copyright (c) 2014 Couchbase, Inc. 2// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 3// except in compliance with the License. You may obtain a copy of the License at 4// http://www.apache.org/licenses/LICENSE-2.0 5// Unless required by applicable law or agreed to in writing, software distributed under the 6// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 7// either express or implied. See the License for the specific language governing permissions 8// and limitations under the License. 9 10package plan 11 12import ( 13 "encoding/json" 14 15 "github.com/couchbase/query/datastore" 16 "github.com/couchbase/query/expression" 17 "github.com/couchbase/query/expression/parser" 18) 19 20type Ranges2 []*Range2 21 22type Range2 struct { 23 Low expression.Expression 24 High expression.Expression 25 Inclusion datastore.Inclusion 26} 27 28func NewRange2(low, high expression.Expression, incl datastore.Inclusion) *Range2 { 29 return &Range2{ 30 Low: low, 31 High: high, 32 Inclusion: incl, 33 } 34} 35 36func (this *Range2) Copy() *Range2 { 37 return &Range2{ 38 Low: expression.Copy(this.Low), 39 High: expression.Copy(this.High), 40 Inclusion: this.Inclusion, 41 } 42} 43 44func (this *Range2) EquivalentTo(other *Range2) bool { 45 return this == other || (this.Inclusion == other.Inclusion && 46 expression.Equivalent(this.Low, other.Low) && 47 expression.Equivalent(this.High, other.High)) 48} 49 50func (this *Range2) EqualRange() bool { 51 return (this.Inclusion == datastore.BOTH) && (this.Low != nil && this.High != nil && (this.Low == this.High || this.Low.EquivalentTo(this.High))) 52} 53 54func (this *Range2) MarshalJSON() ([]byte, error) { 55 return json.Marshal(this.MarshalBase(nil)) 56} 57 58func (this *Range2) MarshalBase(f func(map[string]interface{})) map[string]interface{} { 59 r := map[string]interface{}{ 60 "inclusion": this.Inclusion, 61 } 62 63 if this.Low != nil { 64 r["low"] = this.Low 65 } 66 67 if this.High != nil { 68 r["high"] = this.High 69 } 70 71 if f != nil { 72 f(r) 73 } 74 return r 75} 76 77func (this *Range2) UnmarshalJSON(body []byte) error { 78 var _unmarshalled struct { 79 Low string `json:"low"` 80 High string `json:"high"` 81 Inclusion datastore.Inclusion `json:"inclusion"` 82 } 83 84 err := json.Unmarshal(body, &_unmarshalled) 85 if err != nil { 86 return err 87 } 88 89 if _unmarshalled.Low != "" { 90 this.Low, err = parser.Parse(_unmarshalled.Low) 91 if err != nil { 92 return err 93 } 94 } 95 96 if _unmarshalled.High != "" { 97 this.High, err = parser.Parse(_unmarshalled.High) 98 if err != nil { 99 return err 100 } 101 } 102 103 this.Inclusion = _unmarshalled.Inclusion 104 return nil 105} 106 107func (this Ranges2) Copy() Ranges2 { 108 ranges := make(Ranges2, len(this)) 109 for i, r := range this { 110 if r != nil { 111 ranges[i] = r.Copy() 112 } 113 } 114 115 return ranges 116} 117 118func (this Ranges2) EquivalentTo(other Ranges2) bool { 119 120 if len(this) != len(other) { 121 return false 122 } 123 124 for i := 0; i < len(this); i++ { 125 if this[i] == other[i] { 126 continue 127 } 128 129 if this[i] == nil || other[i] == nil { 130 return false 131 } 132 133 if !this[i].EquivalentTo(other[i]) { 134 return false 135 } 136 } 137 138 return true 139} 140 141func (this *Range2) String() string { 142 bytes, _ := this.MarshalJSON() 143 return string(bytes) 144} 145 146type Spans2 []*Span2 147 148type Span2 struct { 149 Seek expression.Expressions 150 Ranges Ranges2 151 Exact bool 152} 153 154func NewSpan2(seek expression.Expressions, ranges Ranges2, exact bool) *Span2 { 155 return &Span2{ 156 Seek: seek, 157 Ranges: ranges, 158 Exact: exact, 159 } 160} 161 162func (this *Span2) Copy() *Span2 { 163 return &Span2{ 164 Seek: expression.CopyExpressions(this.Seek), 165 Ranges: this.Ranges.Copy(), 166 Exact: this.Exact, 167 } 168} 169 170func (this *Span2) EquivalentTo(other *Span2) bool { 171 return this == other || (this.Exact == other.Exact && 172 expression.Equivalents(this.Seek, other.Seek) && 173 this.Ranges.EquivalentTo(other.Ranges)) 174} 175 176func (this *Span2) Empty() bool { 177 for i := 0; i < len(this.Ranges); i++ { 178 r := this.Ranges[i] 179 if (r.Inclusion&datastore.BOTH) != datastore.BOTH && r.Low != nil { 180 if r.Low == r.High || (r.High != nil && r.Low.EquivalentTo(r.High)) { 181 return true 182 } 183 } 184 185 if r.Low == nil || r.High == nil { 186 continue 187 } 188 189 lv := r.Low.Value() 190 hv := r.High.Value() 191 if lv == nil || hv == nil { 192 continue 193 } 194 195 c := lv.Collate(hv) 196 if c == 0 { 197 if (r.Inclusion & datastore.BOTH) != datastore.BOTH { 198 return true 199 } 200 continue 201 } 202 return c > 0 203 } 204 205 return false 206} 207 208func (this *Span2) MarshalJSON() ([]byte, error) { 209 return json.Marshal(this.MarshalBase(nil)) 210} 211 212func (this *Span2) MarshalBase(f func(map[string]interface{})) map[string]interface{} { 213 r := map[string]interface{}{ 214 "range": this.Ranges, 215 } 216 217 if this.Seek != nil && isNotNull(this.Seek) { 218 r["Seek"] = this.Seek 219 } 220 221 if this.Exact { 222 r["exact"] = this.Exact 223 } 224 225 if f != nil { 226 f(r) 227 } 228 return r 229} 230 231func (this *Span2) UnmarshalJSON(body []byte) error { 232 var _unmarshalled struct { 233 Seek []string `json:"seek"` 234 Ranges []json.RawMessage `json:"range"` 235 Exact bool `json:"exact"` 236 } 237 238 err := json.Unmarshal(body, &_unmarshalled) 239 if err != nil { 240 return err 241 } 242 243 this.Ranges = make(Ranges2, 0, len(_unmarshalled.Ranges)) 244 for _, s := range _unmarshalled.Ranges { 245 r := &Range2{} 246 err = r.UnmarshalJSON(s) 247 if err != nil { 248 return err 249 } 250 this.Ranges = append(this.Ranges, r) 251 } 252 253 if _unmarshalled.Seek != nil { 254 this.Seek = make(expression.Expressions, len(_unmarshalled.Seek)) 255 for j, seekExpr := range _unmarshalled.Seek { 256 this.Seek[j], err = parser.Parse(seekExpr) 257 if err != nil { 258 return err 259 } 260 } 261 } 262 263 this.Exact = _unmarshalled.Exact 264 265 return nil 266} 267 268func (this *Span2) String() string { 269 bytes, _ := this.MarshalJSON() 270 return string(bytes) 271} 272 273func (this Spans2) Copy() Spans2 { 274 spans := make(Spans2, len(this)) 275 for i, s := range this { 276 if s != nil { 277 spans[i] = s.Copy() 278 } 279 } 280 281 return spans 282} 283 284func (this Spans2) EquivalentTo(other Spans2) bool { 285 286 if len(this) != len(other) { 287 return false 288 } 289 290 for i := 0; i < len(this); i++ { 291 if this[i] == other[i] { 292 continue 293 } 294 295 if this[i] == nil || other[i] == nil { 296 return false 297 } 298 299 if !this[i].EquivalentTo(other[i]) { 300 return false 301 } 302 } 303 304 return true 305} 306