forked from cayleygraph/cayley
/
quadstore.go
150 lines (121 loc) · 4.34 KB
/
quadstore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2014 The Cayley Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package graph
// Defines the QuadStore interface. Every backing store must implement at
// least this interface.
//
// Most of these are pretty straightforward. As long as we can surface this
// interface, the rest of the stack will "just work" and we can connect to any
// quad backing store we prefer.
import (
"context"
"errors"
"fmt"
"reflect"
"github.com/cayleygraph/cayley/quad"
)
type BatchQuadStore interface {
ValuesOf(ctx context.Context, vals []Value) ([]quad.Value, error)
}
func ValuesOf(ctx context.Context, qs QuadStore, vals []Value) ([]quad.Value, error) {
if bq, ok := qs.(BatchQuadStore); ok {
return bq.ValuesOf(ctx, vals)
}
out := make([]quad.Value, len(vals))
for i, v := range vals {
out[i] = qs.NameOf(v)
}
return out, nil
}
type QuadStore interface {
// The only way in is through building a transaction, which
// is done by a replication strategy.
ApplyDeltas(in []Delta, opts IgnoreOpts) error
// Given an opaque token, returns the quad for that token from the store.
Quad(Value) quad.Quad
// Given a direction and a token, creates an iterator of links which have
// that node token in that directional field.
QuadIterator(quad.Direction, Value) Iterator
// Returns an iterator enumerating all nodes in the graph.
NodesAllIterator() Iterator
// Returns an iterator enumerating all links in the graph.
QuadsAllIterator() Iterator
// Given a node ID, return the opaque token used by the QuadStore
// to represent that id.
ValueOf(quad.Value) Value
// Given an opaque token, return the node that it represents.
NameOf(Value) quad.Value
// Returns the number of quads currently stored.
Size() int64
// Optimize an iterator in the context of the quad store.
// Suppose we have a better index for the passed tree; this
// gives the QuadStore the opportunity to replace it
// with a more efficient iterator.
OptimizeIterator(it Iterator) (Iterator, bool)
// Close the quad store and clean up. (Flush to disk, cleanly
// sever connections, etc)
Close() error
// Convenience function for speed. Given a quad token and a direction
// return the node token for that direction. Sometimes, a QuadStore
// can do this without going all the way to the backing store, and
// gives the QuadStore the opportunity to make this optimization.
//
// Iterators will call this. At worst, a valid implementation is
//
// qs.ValueOf(qs.Quad(id).Get(dir))
//
QuadDirection(id Value, d quad.Direction) Value
}
type Options map[string]interface{}
var (
typeInt = reflect.TypeOf(int(0))
)
func (d Options) IntKey(key string, def int) (int, error) {
if val, ok := d[key]; ok {
if reflect.TypeOf(val).ConvertibleTo(typeInt) {
i := reflect.ValueOf(val).Convert(typeInt).Int()
return int(i), nil
}
return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val)
}
return def, nil
}
func (d Options) StringKey(key string, def string) (string, error) {
if val, ok := d[key]; ok {
if v, ok := val.(string); ok {
return v, nil
}
return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val)
}
return def, nil
}
func (d Options) BoolKey(key string, def bool) (bool, error) {
if val, ok := d[key]; ok {
if v, ok := val.(bool); ok {
return v, nil
}
return def, fmt.Errorf("Invalid %s parameter type from config: %T", key, val)
}
return def, nil
}
var (
ErrDatabaseExists = errors.New("quadstore: cannot init; database already exists")
ErrNotInitialized = errors.New("quadstore: not initialized")
)
type BulkLoader interface {
// BulkLoad loads Quads from a quad.Unmarshaler in bulk to the QuadStore.
// It returns ErrCannotBulkLoad if bulk loading is not possible. For example if
// you cannot load in bulk to a non-empty database, and the db is non-empty.
BulkLoad(quad.Reader) error
}