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  }