github.com/cayleygraph/cayley@v0.7.7/graph/quadstore.go (about) 1 // Copyright 2014 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 graph 16 17 // Defines the QuadStore interface. Every backing store must implement at 18 // least this interface. 19 // 20 // Most of these are pretty straightforward. As long as we can surface this 21 // interface, the rest of the stack will "just work" and we can connect to any 22 // quad backing store we prefer. 23 24 import ( 25 "context" 26 "errors" 27 "fmt" 28 "reflect" 29 30 "github.com/cayleygraph/quad" 31 ) 32 33 type BatchQuadStore interface { 34 ValuesOf(ctx context.Context, vals []Ref) ([]quad.Value, error) 35 RefsOf(ctx context.Context, nodes []quad.Value) ([]Ref, error) 36 } 37 38 func ValuesOf(ctx context.Context, qs Namer, vals []Ref) ([]quad.Value, error) { 39 if bq, ok := qs.(BatchQuadStore); ok { 40 return bq.ValuesOf(ctx, vals) 41 } 42 out := make([]quad.Value, len(vals)) 43 for i, v := range vals { 44 out[i] = qs.NameOf(v) 45 } 46 return out, nil 47 } 48 49 func RefsOf(ctx context.Context, qs QuadStore, nodes []quad.Value) ([]Ref, error) { 50 if bq, ok := qs.(BatchQuadStore); ok { 51 return bq.RefsOf(ctx, nodes) 52 } 53 values := make([]Ref, len(nodes)) 54 for i, node := range nodes { 55 value := qs.ValueOf(node) 56 if value == nil { 57 return nil, fmt.Errorf("not found: %v", node) 58 } 59 values[i] = value 60 } 61 return values, nil 62 } 63 64 type Namer interface { 65 // Given a node ID, return the opaque token used by the QuadStore 66 // to represent that id. 67 ValueOf(quad.Value) Ref 68 // Given an opaque token, return the node that it represents. 69 NameOf(Ref) quad.Value 70 } 71 72 type QuadIndexer interface { 73 // Given an opaque token, returns the quad for that token from the store. 74 Quad(Ref) quad.Quad 75 76 // Given a direction and a token, creates an iterator of links which have 77 // that node token in that directional field. 78 QuadIterator(quad.Direction, Ref) Iterator 79 80 // QuadIteratorSize returns an estimated size of an iterator. 81 QuadIteratorSize(ctx context.Context, d quad.Direction, v Ref) (Size, error) 82 83 // Convenience function for speed. Given a quad token and a direction 84 // return the node token for that direction. Sometimes, a QuadStore 85 // can do this without going all the way to the backing store, and 86 // gives the QuadStore the opportunity to make this optimization. 87 // 88 // Iterators will call this. At worst, a valid implementation is 89 // 90 // qs.ValueOf(qs.Quad(id).Get(dir)) 91 // 92 QuadDirection(id Ref, d quad.Direction) Ref 93 } 94 95 // Size of a graph (either in nodes or quads). 96 type Size struct { 97 Size int64 98 Exact bool 99 } 100 101 // Stats of a graph. 102 type Stats struct { 103 Nodes Size // number of nodes 104 Quads Size // number of quads 105 } 106 107 type QuadStore interface { 108 Namer 109 QuadIndexer 110 111 // The only way in is through building a transaction, which 112 // is done by a replication strategy. 113 ApplyDeltas(in []Delta, opts IgnoreOpts) error 114 115 // NewQuadWriter starts a batch quad import process. 116 // The order of changes is not guaranteed, neither is the order and result of concurrent ApplyDeltas. 117 NewQuadWriter() (quad.WriteCloser, error) 118 119 // Returns an iterator enumerating all nodes in the graph. 120 NodesAllIterator() Iterator 121 122 // Returns an iterator enumerating all links in the graph. 123 QuadsAllIterator() Iterator 124 125 // Stats returns the number of nodes and quads currently stored. 126 // Exact flag controls the correctness of the value. It can be an estimation, or a precise calculation. 127 // The quadstore may have a fast way of retrieving the precise stats, in this case it may ignore 'exact' 128 // flag and always return correct stats (with an appropriate flags set in the output). 129 Stats(ctx context.Context, exact bool) (Stats, error) 130 131 // Close the quad store and clean up. (Flush to disk, cleanly 132 // sever connections, etc) 133 Close() error 134 } 135 136 type Options map[string]interface{} 137 138 var ( 139 typeInt = reflect.TypeOf(int(0)) 140 ) 141 142 func (d Options) IntKey(key string, def int) (int, error) { 143 if val, ok := d[key]; ok { 144 if reflect.TypeOf(val).ConvertibleTo(typeInt) { 145 i := reflect.ValueOf(val).Convert(typeInt).Int() 146 return int(i), nil 147 } 148 149 return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val) 150 } 151 return def, nil 152 } 153 154 func (d Options) StringKey(key string, def string) (string, error) { 155 if val, ok := d[key]; ok { 156 if v, ok := val.(string); ok { 157 return v, nil 158 } 159 160 return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val) 161 } 162 163 return def, nil 164 } 165 166 func (d Options) BoolKey(key string, def bool) (bool, error) { 167 if val, ok := d[key]; ok { 168 if v, ok := val.(bool); ok { 169 return v, nil 170 } 171 172 return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val) 173 } 174 175 return def, nil 176 } 177 178 var ( 179 ErrDatabaseExists = errors.New("quadstore: cannot init; database already exists") 180 ErrNotInitialized = errors.New("quadstore: not initialized") 181 ) 182 183 type BulkLoader interface { 184 // BulkLoad loads Quads from a quad.Unmarshaler in bulk to the QuadStore. 185 // It returns ErrCannotBulkLoad if bulk loading is not possible. For example if 186 // you cannot load in bulk to a non-empty database, and the db is non-empty. 187 BulkLoad(quad.Reader) error 188 }