github.com/cayleygraph/cayley@v0.7.7/graph/iterator/resolver.go (about) 1 // Copyright 2018 The Cayley Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package iterator 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/cayleygraph/cayley/graph" 22 "github.com/cayleygraph/quad" 23 ) 24 25 var _ graph.IteratorFuture = &Resolver{} 26 27 // A Resolver iterator consists of it's order, an index (where it is in the, 28 // process of iterating) and a store to resolve values from. 29 type Resolver struct { 30 it *resolver 31 graph.Iterator 32 } 33 34 // Creates a new Resolver iterator. 35 func NewResolver(qs graph.QuadStore, nodes ...quad.Value) *Resolver { 36 it := &Resolver{ 37 it: newResolver(qs, nodes...), 38 } 39 it.Iterator = graph.NewLegacy(it.it, it) 40 return it 41 } 42 43 func (it *Resolver) AsShape() graph.IteratorShape { 44 it.Close() 45 return it.it 46 } 47 48 var _ graph.IteratorShapeCompat = (*resolver)(nil) 49 50 // A Resolver iterator consists of it's order, an index (where it is in the, 51 // process of iterating) and a store to resolve values from. 52 type resolver struct { 53 qs graph.QuadStore 54 order []quad.Value 55 } 56 57 // Creates a new Resolver iterator. 58 func newResolver(qs graph.QuadStore, nodes ...quad.Value) *resolver { 59 it := &resolver{ 60 qs: qs, 61 order: make([]quad.Value, len(nodes)), 62 } 63 copy(it.order, nodes) 64 return it 65 } 66 67 func (it *resolver) Iterate() graph.Scanner { 68 return newResolverNext(it.qs, it.order) 69 } 70 71 func (it *resolver) Lookup() graph.Index { 72 return newResolverContains(it.qs, it.order) 73 } 74 75 func (it *resolver) AsLegacy() graph.Iterator { 76 it2 := &Resolver{it: it} 77 it2.Iterator = graph.NewLegacy(it, it2) 78 return it2 79 } 80 81 func (it *resolver) String() string { 82 return fmt.Sprintf("Resolver(%v)", it.order) 83 } 84 85 func (it *resolver) SubIterators() []graph.IteratorShape { 86 return nil 87 } 88 89 // Returns a Null iterator if it's empty so that upstream iterators can optimize it 90 // away, otherwise there is no optimization. 91 func (it *resolver) Optimize(ctx context.Context) (graph.IteratorShape, bool) { 92 if len(it.order) == 0 { 93 return newNull(), true 94 } 95 return it, false 96 } 97 98 func (it *resolver) Stats(ctx context.Context) (graph.IteratorCosts, error) { 99 return graph.IteratorCosts{ 100 // Next is (presumably) O(1) from store 101 NextCost: 1, 102 ContainsCost: 1, 103 Size: graph.Size{ 104 Size: int64(len(it.order)), 105 Exact: true, 106 }, 107 }, nil 108 } 109 110 // A Resolver iterator consists of it's order, an index (where it is in the, 111 // process of iterating) and a store to resolve values from. 112 type resolverNext struct { 113 qs graph.QuadStore 114 order []quad.Value 115 values []graph.Ref 116 cached bool 117 index int 118 err error 119 result graph.Ref 120 } 121 122 // Creates a new Resolver iterator. 123 func newResolverNext(qs graph.QuadStore, nodes []quad.Value) *resolverNext { 124 it := &resolverNext{ 125 qs: qs, 126 order: make([]quad.Value, len(nodes)), 127 } 128 copy(it.order, nodes) 129 return it 130 } 131 132 func (it *resolverNext) Close() error { 133 return nil 134 } 135 136 func (it *resolverNext) TagResults(dst map[string]graph.Ref) {} 137 138 func (it *resolverNext) String() string { 139 return fmt.Sprintf("ResolverNext(%v, %v)", it.order, it.values) 140 } 141 142 // Resolve nodes to values 143 func (it *resolverNext) resolve(ctx context.Context) error { 144 values, err := graph.RefsOf(ctx, it.qs, it.order) 145 if err != nil { 146 return err 147 } 148 it.values = make([]graph.Ref, len(it.order)) 149 for i, value := range values { 150 it.values[i] = value 151 } 152 it.order = nil 153 it.cached = true 154 return nil 155 } 156 157 // Next advances the iterator. 158 func (it *resolverNext) Next(ctx context.Context) bool { 159 if !it.cached { 160 it.err = it.resolve(ctx) 161 if it.err != nil { 162 return false 163 } 164 } 165 if it.index >= len(it.values) { 166 it.result = nil 167 return false 168 } 169 it.result = it.values[it.index] 170 it.index++ 171 return true 172 } 173 174 func (it *resolverNext) Err() error { 175 return it.err 176 } 177 178 func (it *resolverNext) Result() graph.Ref { 179 return it.result 180 } 181 182 func (it *resolverNext) NextPath(ctx context.Context) bool { 183 return false 184 } 185 186 // A Resolver iterator consists of it's order, an index (where it is in the, 187 // process of iterating) and a store to resolve values from. 188 type resolverContains struct { 189 qs graph.QuadStore 190 order []quad.Value 191 nodes map[interface{}]quad.Value 192 cached bool 193 err error 194 result graph.Ref 195 } 196 197 // Creates a new Resolver iterator. 198 func newResolverContains(qs graph.QuadStore, nodes []quad.Value) *resolverContains { 199 it := &resolverContains{ 200 qs: qs, 201 order: make([]quad.Value, len(nodes)), 202 } 203 copy(it.order, nodes) 204 return it 205 } 206 207 func (it *resolverContains) Close() error { 208 return nil 209 } 210 211 func (it *resolverContains) TagResults(dst map[string]graph.Ref) {} 212 213 func (it *resolverContains) String() string { 214 return fmt.Sprintf("ResolverContains(%v, %v)", it.order, it.nodes) 215 } 216 217 // Resolve nodes to values 218 func (it *resolverContains) resolve(ctx context.Context) error { 219 values, err := graph.RefsOf(ctx, it.qs, it.order) 220 if err != nil { 221 return err 222 } 223 // Generally there are going to be no/few duplicates given 224 // so allocate maps large enough to accommodate all 225 it.nodes = make(map[interface{}]quad.Value, len(it.order)) 226 for index, value := range values { 227 node := it.order[index] 228 it.nodes[value.Key()] = node 229 } 230 it.order = nil 231 it.cached = true 232 return nil 233 } 234 235 // Check if the passed value is equal to one of the order stored in the iterator. 236 func (it *resolverContains) Contains(ctx context.Context, value graph.Ref) bool { 237 if !it.cached { 238 it.err = it.resolve(ctx) 239 if it.err != nil { 240 return false 241 } 242 } 243 _, ok := it.nodes[value.Key()] 244 if ok { 245 it.result = value 246 } 247 return ok 248 } 249 250 func (it *resolverContains) Err() error { 251 return it.err 252 } 253 254 func (it *resolverContains) Result() graph.Ref { 255 return it.result 256 } 257 258 func (it *resolverContains) NextPath(ctx context.Context) bool { 259 return false 260 }