Skip to content

Commit 06a0f56

Browse files
authored
Add Graph, Index and Cursor missing fields (#378)
* Add Graph, Index and Cursor missing fields * Expose graph fields * Skip tests
1 parent 9724218 commit 06a0f56

8 files changed

+238
-28
lines changed

collection_indexes_impl.go

+23-14
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,32 @@ import (
2828
)
2929

3030
type indexData struct {
31-
ID string `json:"id,omitempty"`
32-
Type string `json:"type"`
33-
Fields []string `json:"fields,omitempty"`
34-
Unique *bool `json:"unique,omitempty"`
35-
Deduplicate *bool `json:"deduplicate,omitempty"`
36-
Sparse *bool `json:"sparse,omitempty"`
37-
GeoJSON *bool `json:"geoJson,omitempty"`
38-
InBackground *bool `json:"inBackground,omitempty"`
39-
Estimates *bool `json:"estimates,omitempty"`
40-
MinLength int `json:"minLength,omitempty"`
41-
ExpireAfter int `json:"expireAfter,omitempty"`
42-
Name string `json:"name,omitempty"`
43-
FieldValueTypes string `json:"fieldValueTypes,omitempty"`
31+
ID string `json:"id,omitempty"`
32+
Type string `json:"type"`
33+
Fields []string `json:"fields,omitempty"`
34+
Unique *bool `json:"unique,omitempty"`
35+
Deduplicate *bool `json:"deduplicate,omitempty"`
36+
Sparse *bool `json:"sparse,omitempty"`
37+
GeoJSON *bool `json:"geoJson,omitempty"`
38+
InBackground *bool `json:"inBackground,omitempty"`
39+
Estimates *bool `json:"estimates,omitempty"`
40+
MaxNumCoverCells int `json:"maxNumCoverCells,omitempty"`
41+
MinLength int `json:"minLength,omitempty"`
42+
ExpireAfter int `json:"expireAfter,omitempty"`
43+
Name string `json:"name,omitempty"`
44+
FieldValueTypes string `json:"fieldValueTypes,omitempty"`
45+
IsNewlyCreated *bool `json:"isNewlyCreated,omitempty"`
46+
SelectivityEstimate int `json:"selectivityEstimate,omitempty"`
47+
BestIndexedLevel int `json:"bestIndexedLevel,omitempty"`
48+
WorstIndexedLevel int `json:"worstIndexedLevel,omitempty"`
49+
50+
ArangoError `json:",inline"`
4451
}
4552

4653
type indexListResponse struct {
47-
Indexes []indexData `json:"indexes,omitempty"`
54+
Indexes []indexData `json:"indexes,omitempty"`
55+
Identifiers map[string]indexData `json:"identifiers,omitempty"`
56+
ArangoError
4857
}
4958

5059
// Index opens a connection to an existing index within the collection.

cursor_impl.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ type cursorStats struct {
7272
// The total number of documents that matched the search condition if the query's final LIMIT statement were not present.
7373
FullCountInt int64 `json:"fullCount,omitempty"`
7474
// Query execution time (wall-clock time). value will be set from the outside
75-
ExecutionTimeInt float64 `json:"executionTime,omitempty"`
75+
ExecutionTimeInt float64 `json:"executionTime,omitempty"`
76+
Nodes []cursorPlanNodes `json:"nodes,omitempty"`
77+
HttpRequests int64 `json:"httpRequests,omitempty"`
78+
PeakMemoryUsage int64 `json:"peakMemoryUsage,omitempty"`
7679
}
7780

7881
type cursorPlan struct {
@@ -86,9 +89,10 @@ type cursorPlan struct {
8689
}
8790

8891
type cursorExtra struct {
89-
Stats cursorStats `json:"stats,omitempty"`
90-
Profile cursorProfile `json:"profile,omitempty"`
91-
Plan *cursorPlan `json:"plan,omitempty"`
92+
Stats cursorStats `json:"stats,omitempty"`
93+
Profile cursorProfile `json:"profile,omitempty"`
94+
Plan *cursorPlan `json:"plan,omitempty"`
95+
Warnings []string `json:"warnings,omitempty"`
9296
}
9397

9498
func (c cursorExtra) GetStatistics() QueryStatistics {
@@ -137,11 +141,14 @@ type cursorPlanNodes map[string]interface{}
137141
type cursorProfile map[string]interface{}
138142

139143
type cursorData struct {
144+
Key string `json:"_key,omitempty"`
140145
Count int64 `json:"count,omitempty"` // the total number of result documents available (only available if the query was executed with the count attribute set)
141146
ID string `json:"id"` // id of temporary cursor created on the server (optional, see above)
142147
Result []*RawObject `json:"result,omitempty"` // an array of result documents (might be empty if query has no results)
143148
HasMore bool `json:"hasMore,omitempty"` // A boolean indicator whether there are more results available for the cursor on the server
144149
Extra cursorExtra `json:"extra"`
150+
Cached bool `json:"cached,omitempty"`
151+
ArangoError
145152
}
146153

147154
// relPath creates the relative path to this cursor (`_db/<db-name>/_api/cursor`)

graph.go

+30
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,34 @@ type Graph interface {
4747

4848
// Vertex collection functions
4949
GraphVertexCollections
50+
51+
// ID returns the id of the graph.
52+
ID() string
53+
54+
// Key returns the key of the graph.
55+
Key() DocumentID
56+
57+
// Rev returns the revision of the graph.
58+
Rev() string
59+
60+
// EdgeDefinitions returns the edge definitions of the graph.
61+
EdgeDefinitions() []EdgeDefinition
62+
63+
// SmartGraphAttribute returns the attributes of a smart graph if there are any.
64+
SmartGraphAttribute() string
65+
66+
// MinReplicationFactor returns the minimum replication factor for the graph.
67+
MinReplicationFactor() int
68+
69+
// NumberOfShards returns the number of shards for the graph.
70+
NumberOfShards() int
71+
72+
// OrphanCollections returns the orphan collcetions of the graph.
73+
OrphanCollections() []string
74+
75+
// ReplicationFactor returns the current replication factor.
76+
ReplicationFactor() int
77+
78+
// WriteConcern returns the write concern setting of the graph.
79+
WriteConcern() int
5080
}

graph_edge_collections_impl.go

+23
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,33 @@ type graphDefinition struct {
3434
IsDisjoint bool `json:"isDisjoint,omitempty"`
3535

3636
EdgeDefinitions []EdgeDefinition `json:"edgeDefinitions,omitempty"`
37+
38+
NumberOfShards int `json:"numberOfShards,omitempty"`
39+
OrphanCollections []string `json:"orphanCollections,omitempty"`
40+
41+
// Deprecated: use 'WriteConcern' instead.
42+
MinReplicationFactor int `json:"minReplicationFactor,omitempty"`
43+
WriteConcern int `json:"writeConcern,omitempty"`
44+
45+
// ReplicationFactor is the number of replication factor that is used for every collection within this graph.
46+
// Cannot be modified later.
47+
ReplicationFactor graphReplicationFactor `json:"replicationFactor,omitempty"`
48+
49+
// This field must be set to the attribute that will be used for sharding or smart graphs.
50+
// All vertices are required to have this attribute set. Edges derive the attribute from their connected vertices.
51+
// This requires ArangoDB Enterprise Edition.
52+
SmartGraphAttribute string `json:"smartGraphAttribute,omitempty"`
53+
54+
Initial *string `json:"initial,omitempty"`
55+
InitialCid int `json:"initialCid,omitempty"`
56+
ID string `json:"_id"`
57+
Key DocumentID `json:"_key"`
58+
Rev string `json:"_rev"`
3759
}
3860

3961
type getGraphResponse struct {
4062
Graph graphDefinition `json:"graph"`
63+
ArangoError
4164
}
4265

4366
// EdgeCollection opens a connection to an existing edge-collection within the graph.

graph_impl.go

+50
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,56 @@ func (g *graph) Name() string {
7171
return g.input.Name
7272
}
7373

74+
// ID returns the id of the graph.
75+
func (g *graph) ID() string {
76+
return g.input.ID
77+
}
78+
79+
// Key returns the key of the graph.
80+
func (g *graph) Key() DocumentID {
81+
return g.input.Key
82+
}
83+
84+
// Key returns the key of the graph.
85+
func (g *graph) Rev() string {
86+
return g.input.Rev
87+
}
88+
89+
// EdgeDefinitions returns the edge definitions of the graph.
90+
func (g *graph) EdgeDefinitions() []EdgeDefinition {
91+
return g.input.EdgeDefinitions
92+
}
93+
94+
// IsSmart returns the isSmart setting of the graph.
95+
func (g *graph) SmartGraphAttribute() string {
96+
return g.input.SmartGraphAttribute
97+
}
98+
99+
// MinReplicationFactor returns the minimum replication factor for the graph.
100+
func (g *graph) MinReplicationFactor() int {
101+
return g.input.MinReplicationFactor
102+
}
103+
104+
// NumberOfShards returns the number of shards for the graph.
105+
func (g *graph) NumberOfShards() int {
106+
return g.input.NumberOfShards
107+
}
108+
109+
// OrphanCollections returns the orphan collcetions of the graph.
110+
func (g *graph) OrphanCollections() []string {
111+
return g.input.OrphanCollections
112+
}
113+
114+
// ReplicationFactor returns the current replication factor.
115+
func (g *graph) ReplicationFactor() int {
116+
return int(g.input.ReplicationFactor)
117+
}
118+
119+
// WriteConcern returns the write concern setting of the graph.
120+
func (g *graph) WriteConcern() int {
121+
return g.input.WriteConcern
122+
}
123+
74124
// Remove removes the entire graph.
75125
// If the graph does not exist, a NotFoundError is returned.
76126
func (g *graph) Remove(ctx context.Context) error {

test/context_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func TestContextParentNil(t *testing.T) {
5555

5656
func TestContextWithArangoQueueTimeoutParams(t *testing.T) {
5757
c := createClientFromEnv(t, true)
58+
skipBelowVersion(c, "3.9", t)
5859

5960
t.Run("without timout", func(t *testing.T) {
6061
_, err := c.Version(context.Background())

test/graph_test.go

+94-10
Original file line numberDiff line numberDiff line change
@@ -46,20 +46,22 @@ func ensureGraph(ctx context.Context, db driver.Database, name string, options *
4646

4747
// TestCreateGraph creates a graph and then checks that it exists.
4848
func TestCreateGraph(t *testing.T) {
49+
ctx := context.Background()
4950
c := createClientFromEnv(t, true)
50-
db := ensureDatabase(nil, c, "graph_test", nil, t)
51+
db := ensureDatabase(ctx, c, "graph_test", nil, t)
5152
name := "test_create_graph"
52-
if _, err := db.CreateGraphV2(nil, name, nil); err != nil {
53+
54+
if _, err := db.CreateGraphV2(ctx, name, nil); err != nil {
5355
t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
5456
}
5557
// Graph must exist now
56-
if found, err := db.GraphExists(nil, name); err != nil {
58+
if found, err := db.GraphExists(ctx, name); err != nil {
5759
t.Errorf("GraphExists('%s') failed: %s", name, describe(err))
5860
} else if !found {
5961
t.Errorf("GraphExists('%s') return false, expected true", name)
6062
}
6163
// Graph must be listed
62-
if list, err := db.Graphs(nil); err != nil {
64+
if list, err := db.Graphs(ctx); err != nil {
6365
t.Errorf("Graphs failed: %s", describe(err))
6466
} else {
6567
found := false
@@ -74,34 +76,116 @@ func TestCreateGraph(t *testing.T) {
7476
}
7577
}
7678
// Open graph
77-
if g, err := db.Graph(nil, name); err != nil {
79+
if g, err := db.Graph(ctx, name); err != nil {
7880
t.Errorf("Graph('%s') failed: %s", name, describe(err))
7981
} else if g.Name() != name {
8082
t.Errorf("Graph.Name wrong. Expected '%s', got '%s'", name, g.Name())
8183
}
8284
}
8385

86+
// TestCreateGraphWithOptions creates a graph with options then checks if each options is set correctly.
87+
func TestCreateGraphWithOptions(t *testing.T) {
88+
ctx := context.Background()
89+
c := createClientFromEnv(t, true)
90+
skipBelowVersion(c, "3.6", t)
91+
skipNoCluster(c, t)
92+
93+
db := ensureDatabase(ctx, c, "graph_test", nil, t)
94+
name := "test_create_graph_2"
95+
96+
options := &driver.CreateGraphOptions{
97+
OrphanVertexCollections: []string{"orphan1", "orphan2"},
98+
EdgeDefinitions: []driver.EdgeDefinition{
99+
{
100+
Collection: "coll",
101+
To: []string{"to-coll1"},
102+
From: []string{"from-coll1"},
103+
},
104+
},
105+
NumberOfShards: 2,
106+
ReplicationFactor: 3,
107+
WriteConcern: 2,
108+
SmartGraphAttribute: "orphan1",
109+
}
110+
111+
if _, err := db.CreateGraphV2(ctx, name, options); err != nil {
112+
t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
113+
}
114+
// Graph must exist now
115+
if found, err := db.GraphExists(ctx, name); err != nil {
116+
t.Errorf("GraphExists('%s') failed: %s", name, describe(err))
117+
} else if !found {
118+
t.Errorf("GraphExists('%s') return false, expected true", name)
119+
}
120+
// Graph must be listed
121+
if list, err := db.Graphs(ctx); err != nil {
122+
t.Errorf("Graphs failed: %s", describe(err))
123+
} else {
124+
found := false
125+
for _, g := range list {
126+
if g.Name() == name {
127+
found = true
128+
break
129+
}
130+
}
131+
if !found {
132+
t.Errorf("Graph '%s' not found in list", name)
133+
}
134+
}
135+
136+
// Open graph
137+
g, err := db.Graph(ctx, name)
138+
if err != nil {
139+
t.Errorf("Graph('%s') failed: %s", name, describe(err))
140+
} else if g.Name() != name {
141+
t.Errorf("Graph.Name wrong. Expected '%s', got '%s'", name, g.Name())
142+
}
143+
144+
if g.NumberOfShards() != options.NumberOfShards {
145+
t.Errorf("Graph.NumberOfShards wrong. Expected '%d', got '%d'", options.NumberOfShards, g.NumberOfShards())
146+
}
147+
if g.ReplicationFactor() != options.ReplicationFactor {
148+
t.Errorf("Graph.ReplicationFactor wrong. Expected '%d', got '%d'", options.ReplicationFactor, g.ReplicationFactor())
149+
}
150+
if g.WriteConcern() != options.WriteConcern {
151+
t.Errorf("Graph.WriteConcern wrong. Expected '%d', got '%d'", options.WriteConcern, g.WriteConcern())
152+
}
153+
if g.EdgeDefinitions()[0].Collection != options.EdgeDefinitions[0].Collection {
154+
t.Errorf("Graph.EdgeDefinitions.collection wrong. Expected '%s', got '%s'", options.EdgeDefinitions[0].Collection, g.EdgeDefinitions()[0].Collection)
155+
}
156+
if g.EdgeDefinitions()[0].From[0] != options.EdgeDefinitions[0].From[0] {
157+
t.Errorf("Graph.EdgeDefinitions.from wrong. Expected '%s', got '%s'", options.EdgeDefinitions[0].From[0], g.EdgeDefinitions()[0].From[0])
158+
}
159+
if g.EdgeDefinitions()[0].To[0] != options.EdgeDefinitions[0].To[0] {
160+
t.Errorf("Graph.EdgeDefinitions.to wrong. Expected '%s', got '%s'", options.EdgeDefinitions[0].To[0], g.EdgeDefinitions()[0].To[0])
161+
}
162+
if g.OrphanCollections()[0] != options.OrphanVertexCollections[0] && g.OrphanCollections()[1] != options.OrphanVertexCollections[1] {
163+
t.Errorf("Graph.IsSmart wrong. Expected '%v', got '%v'", options.OrphanVertexCollections, g.OrphanCollections())
164+
}
165+
}
166+
84167
// TestRemoveGraph creates a graph and then removes it.
85168
func TestRemoveGraph(t *testing.T) {
169+
ctx := context.Background()
86170
c := createClientFromEnv(t, true)
87-
db := ensureDatabase(nil, c, "graph_test", nil, t)
171+
db := ensureDatabase(ctx, c, "graph_test", nil, t)
88172
name := "test_remove_graph"
89-
g, err := db.CreateGraphV2(nil, name, nil)
173+
g, err := db.CreateGraphV2(ctx, name, nil)
90174
if err != nil {
91175
t.Fatalf("Failed to create graph '%s': %s", name, describe(err))
92176
}
93177
// Graph must exist now
94-
if found, err := db.GraphExists(nil, name); err != nil {
178+
if found, err := db.GraphExists(ctx, name); err != nil {
95179
t.Errorf("GraphExists('%s') failed: %s", name, describe(err))
96180
} else if !found {
97181
t.Errorf("GraphExists('%s') return false, expected true", name)
98182
}
99183
// Now remove it
100-
if err := g.Remove(nil); err != nil {
184+
if err := g.Remove(ctx); err != nil {
101185
t.Fatalf("Failed to remove graph '%s': %s", name, describe(err))
102186
}
103187
// Graph must not exist now
104-
if found, err := db.GraphExists(nil, name); err != nil {
188+
if found, err := db.GraphExists(ctx, name); err != nil {
105189
t.Errorf("GraphExists('%s') failed: %s", name, describe(err))
106190
} else if found {
107191
t.Errorf("GraphExists('%s') return true, expected false", name)

v2/tests/context_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ import (
3434
func TestContextWithArangoQueueTimeoutParams(t *testing.T) {
3535
c := newClient(t, connectionJsonHttp(t))
3636

37+
version, err := c.Version(context.Background())
38+
require.NoError(t, err)
39+
if version.Version.CompareTo("3.9.0") < 0 {
40+
t.Skipf("Version of the ArangoDB should be at least 3.9.0")
41+
}
42+
3743
t.Run("without timout", func(t *testing.T) {
3844
_, err := c.Version(context.Background())
3945
require.NoError(t, err)

0 commit comments

Comments
 (0)