Skip to content

Commit 6e51632

Browse files
authored
[Feature] [3.7] Extend graph parameters (#275)
1 parent 13b09cd commit 6e51632

File tree

8 files changed

+271
-21
lines changed

8 files changed

+271
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- Use internal coordinator communication for cursors if specified coordinator was not found on endpoint list
55
- Add support for Overwrite Mode (ArangoDB 3.7)
66
- Add support for Schema Collection options (ArangoDB 3.7)
7+
- Add support for Disjoint and Satellite Graphs options (ArangoDB 3.7)
78

89
## [1.0.0](https://github.com/arangodb/go-driver/tree/1.0.0) (N/A)
910
- Enable proper CHANGELOG and versioning

database_graphs.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ package driver
2424

2525
import "context"
2626

27+
const (
28+
SatelliteGraph = -100
29+
)
30+
2731
// DatabaseGraphs provides access to all graphs in a single database.
2832
type DatabaseGraphs interface {
2933
// Graph opens a connection to an existing graph within the database.
@@ -64,6 +68,8 @@ type CreateGraphOptions struct {
6468
// WriteConcern is the number of min replication factor that is used for every collection within this graph.
6569
// Cannot be modified later.
6670
WriteConcern int
71+
// IsDisjoint set isDisjoint flag for Graph. Required ArangoDB 3.7+
72+
IsDisjoint bool
6773
}
6874

6975
// EdgeDefinition contains all information needed to define a single edge in a graph.

database_graphs_impl.go

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ package driver
2424

2525
import (
2626
"context"
27+
"encoding/json"
2728
"path"
29+
30+
"github.com/pkg/errors"
2831
)
2932

3033
// Graph opens a connection to an existing graph within the database.
@@ -42,7 +45,11 @@ func (d *database) Graph(ctx context.Context, name string) (Graph, error) {
4245
if err := resp.CheckStatus(200); err != nil {
4346
return nil, WithStack(err)
4447
}
45-
g, err := newGraph(name, d)
48+
var data getGraphResponse
49+
if err := resp.ParseBody("", &data); err != nil {
50+
return nil, WithStack(err)
51+
}
52+
g, err := newGraph(data.Graph, d)
4653
if err != nil {
4754
return nil, WithStack(err)
4855
}
@@ -70,7 +77,7 @@ func (d *database) GraphExists(ctx context.Context, name string) (bool, error) {
7077
}
7178

7279
type getGraphsResponse struct {
73-
Graphs []DocumentMeta `json:"graphs,omitempty"`
80+
Graphs []graphDefinition `json:"graphs,omitempty"`
7481
}
7582

7683
// Graphs returns a list of all graphs in the database.
@@ -92,7 +99,7 @@ func (d *database) Graphs(ctx context.Context) ([]Graph, error) {
9299
}
93100
result := make([]Graph, 0, len(data.Graphs))
94101
for _, info := range data.Graphs {
95-
g, err := newGraph(info.Key, d)
102+
g, err := newGraph(info, d)
96103
if err != nil {
97104
return nil, WithStack(err)
98105
}
@@ -109,6 +116,40 @@ type createGraphOptions struct {
109116
Options *createGraphAdditionalOptions `json:"options,omitempty"`
110117
}
111118

119+
type graphReplicationFactor int
120+
121+
func (g graphReplicationFactor) MarshalJSON() ([]byte, error) {
122+
switch g {
123+
case SatelliteGraph:
124+
return json.Marshal(replicationFactorSatelliteString)
125+
default:
126+
return json.Marshal(int(g))
127+
}
128+
}
129+
130+
func (g *graphReplicationFactor) UnmarshalJSON(data []byte) error {
131+
var d int
132+
133+
if err := json.Unmarshal(data, &d); err == nil {
134+
*g = graphReplicationFactor(d)
135+
return nil
136+
}
137+
138+
var s string
139+
140+
if err := json.Unmarshal(data, &s); err != nil {
141+
return err
142+
}
143+
144+
switch s {
145+
case replicationFactorSatelliteString:
146+
*g = graphReplicationFactor(SatelliteGraph)
147+
return nil
148+
default:
149+
return errors.Errorf("Unsupported type %s", s)
150+
}
151+
}
152+
112153
type createGraphAdditionalOptions struct {
113154
// SmartGraphAttribute is the attribute name that is used to smartly shard the vertices of a graph.
114155
// Every vertex in this Graph has to have this attribute.
@@ -119,10 +160,12 @@ type createGraphAdditionalOptions struct {
119160
NumberOfShards int `json:"numberOfShards,omitempty"`
120161
// ReplicationFactor is the number of replication factor that is used for every collection within this graph.
121162
// Cannot be modified later.
122-
ReplicationFactor int `json:"replicationFactor,omitempty"`
163+
ReplicationFactor graphReplicationFactor `json:"replicationFactor,omitempty"`
123164
// WriteConcern is the number of min replication factor that is used for every collection within this graph.
124165
// Cannot be modified later.
125166
WriteConcern int `json:"writeConcern,omitempty"`
167+
// IsDisjoint set isDisjoint flag for Graph. Required ArangoDB 3.7+
168+
IsDisjoint bool `json:"isDisjoint,omitempty"`
126169
}
127170

128171
// CreateGraph creates a new graph with given name and options, and opens a connection to it.
@@ -135,12 +178,19 @@ func (d *database) CreateGraph(ctx context.Context, name string, options *Create
135178
input.OrphanVertexCollections = options.OrphanVertexCollections
136179
input.EdgeDefinitions = options.EdgeDefinitions
137180
input.IsSmart = options.IsSmart
138-
if options.SmartGraphAttribute != "" || options.NumberOfShards != 0 {
181+
if options.ReplicationFactor == SatelliteGraph {
182+
input.Options = &createGraphAdditionalOptions{
183+
SmartGraphAttribute: options.SmartGraphAttribute,
184+
ReplicationFactor: graphReplicationFactor(options.ReplicationFactor),
185+
IsDisjoint: options.IsDisjoint,
186+
}
187+
} else if options.SmartGraphAttribute != "" || options.NumberOfShards != 0 {
139188
input.Options = &createGraphAdditionalOptions{
140189
SmartGraphAttribute: options.SmartGraphAttribute,
141190
NumberOfShards: options.NumberOfShards,
142-
ReplicationFactor: options.ReplicationFactor,
191+
ReplicationFactor: graphReplicationFactor(options.ReplicationFactor),
143192
WriteConcern: options.WriteConcern,
193+
IsDisjoint: options.IsDisjoint,
144194
}
145195
}
146196
}
@@ -158,7 +208,11 @@ func (d *database) CreateGraph(ctx context.Context, name string, options *Create
158208
if err := resp.CheckStatus(201, 202); err != nil {
159209
return nil, WithStack(err)
160210
}
161-
g, err := newGraph(name, d)
211+
var data getGraphResponse
212+
if err := resp.ParseBody("", &data); err != nil {
213+
return nil, WithStack(err)
214+
}
215+
g, err := newGraph(data.Graph, d)
162216
if err != nil {
163217
return nil, WithStack(err)
164218
}

graph.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ type Graph interface {
3333
// If the graph does not exist, a NotFoundError is returned.
3434
Remove(ctx context.Context) error
3535

36+
// IsSmart returns true of smart is smart. In case of Community Edition it is always false
37+
IsSmart() bool
38+
39+
// IsSatellite returns true of smart is satellite. In case of Community Edition it is always false
40+
IsSatellite() bool
41+
42+
// IsDisjoint return information if graph have isDisjoint flag set to true
43+
IsDisjoint() bool
44+
3645
// Edge collection functions
3746
GraphEdgeCollections
3847

graph_edge_collections_impl.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,17 @@ import (
2727
"path"
2828
)
2929

30+
type graphDefinition struct {
31+
Name string `json:"name"`
32+
IsSmart bool `json:"isSmart"`
33+
IsSatellite bool `json:"isSatellite"`
34+
IsDisjoint bool `json:"isDisjoint,omitempty"`
35+
36+
EdgeDefinitions []EdgeDefinition `json:"edgeDefinitions,omitempty"`
37+
}
38+
3039
type getGraphResponse struct {
31-
Graph struct {
32-
EdgeDefinitions []EdgeDefinition `json:"edgeDefinitions,omitempty"`
33-
} `json:"graph"`
40+
Graph graphDefinition `json:"graph"`
3441
}
3542

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

graph_impl.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,35 +28,47 @@ import (
2828
)
2929

3030
// newGraph creates a new Graph implementation.
31-
func newGraph(name string, db *database) (Graph, error) {
32-
if name == "" {
31+
func newGraph(input graphDefinition, db *database) (Graph, error) {
32+
if input.Name == "" {
3333
return nil, WithStack(InvalidArgumentError{Message: "name is empty"})
3434
}
3535
if db == nil {
3636
return nil, WithStack(InvalidArgumentError{Message: "db is nil"})
3737
}
3838
return &graph{
39-
name: name,
40-
db: db,
41-
conn: db.conn,
39+
input: input,
40+
db: db,
41+
conn: db.conn,
4242
}, nil
4343
}
4444

4545
type graph struct {
46-
name string
47-
db *database
48-
conn Connection
46+
input graphDefinition
47+
db *database
48+
conn Connection
49+
}
50+
51+
func (g *graph) IsSmart() bool {
52+
return g.input.IsSmart
53+
}
54+
55+
func (g *graph) IsDisjoint() bool {
56+
return g.input.IsDisjoint
57+
}
58+
59+
func (g *graph) IsSatellite() bool {
60+
return g.input.IsSatellite
4961
}
5062

5163
// relPath creates the relative path to this graph (`_db/<db-name>/_api/gharial/<graph-name>`)
5264
func (g *graph) relPath() string {
53-
escapedName := pathEscape(g.name)
65+
escapedName := pathEscape(g.Name())
5466
return path.Join(g.db.relPath(), "_api", "gharial", escapedName)
5567
}
5668

5769
// Name returns the name of the graph.
5870
func (g *graph) Name() string {
59-
return g.name
71+
return g.input.Name
6072
}
6173

6274
// Remove removes the entire graph.

test/graph_creation_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,136 @@ func Test_Graph_AdvancedCreate_Defaults(t *testing.T) {
178178
}
179179
})
180180
}
181+
182+
func TestGraphCreation(t *testing.T) {
183+
// Arrange
184+
ctx := context.Background()
185+
186+
c := createClientFromEnv(t, true)
187+
EnsureVersion(t, ctx, c).MinimumVersion("3.7.0").Cluster().Enterprise()
188+
189+
t.Run("Satellite", func(t *testing.T) {
190+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
191+
192+
// Create
193+
graphID := db.Name() + "_graph"
194+
195+
options, collections := newGraphOpts(db)
196+
197+
options.ReplicationFactor = driver.SatelliteGraph
198+
199+
g, err := db.CreateGraph(ctx, graphID, &options)
200+
require.NoError(t, err)
201+
202+
// Wait for collections to be created
203+
waitForCollections(t, db, collections)
204+
205+
require.True(t, g.IsSatellite())
206+
})
207+
208+
t.Run("Satellite - list", func(t *testing.T) {
209+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
210+
211+
// Create
212+
graphID := db.Name() + "_graph"
213+
214+
options, collections := newGraphOpts(db)
215+
216+
options.ReplicationFactor = driver.SatelliteGraph
217+
218+
g, err := db.CreateGraph(ctx, graphID, &options)
219+
require.NoError(t, err)
220+
221+
// Wait for collections to be created
222+
waitForCollections(t, db, collections)
223+
224+
graphs, err := db.Graphs(ctx)
225+
require.NoError(t, err)
226+
require.Len(t, graphs, 1)
227+
228+
require.Equal(t, g.Name(), graphs[0].Name())
229+
require.True(t, graphs[0].IsSatellite())
230+
})
231+
232+
t.Run("Standard", func(t *testing.T) {
233+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
234+
235+
// Create
236+
graphID := db.Name() + "_graph"
237+
238+
options, collections := newGraphOpts(db)
239+
240+
g, err := db.CreateGraph(ctx, graphID, &options)
241+
require.NoError(t, err)
242+
243+
// Wait for collections to be created
244+
waitForCollections(t, db, collections)
245+
246+
require.False(t, g.IsSatellite())
247+
})
248+
249+
t.Run("Standard - list", func(t *testing.T) {
250+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
251+
252+
// Create
253+
graphID := db.Name() + "_graph"
254+
255+
options, collections := newGraphOpts(db)
256+
257+
g, err := db.CreateGraph(ctx, graphID, &options)
258+
require.NoError(t, err)
259+
260+
// Wait for collections to be created
261+
waitForCollections(t, db, collections)
262+
263+
graphs, err := db.Graphs(ctx)
264+
require.NoError(t, err)
265+
require.Len(t, graphs, 1)
266+
267+
require.Equal(t, g.Name(), graphs[0].Name())
268+
require.False(t, graphs[0].IsSatellite())
269+
})
270+
271+
t.Run("Disjoint", func(t *testing.T) {
272+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
273+
274+
// Create
275+
graphID := db.Name() + "_graph"
276+
277+
options, collections := newGraphOpts(db)
278+
279+
options.IsDisjoint = true
280+
281+
g, err := db.CreateGraph(ctx, graphID, &options)
282+
require.NoError(t, err)
283+
284+
// Wait for collections to be created
285+
waitForCollections(t, db, collections)
286+
287+
require.True(t, g.IsDisjoint())
288+
})
289+
290+
t.Run("Disjoint - list", func(t *testing.T) {
291+
db := ensureDatabase(ctx, c, databaseName("graph", "create", "defaults"), nil, t)
292+
293+
// Create
294+
graphID := db.Name() + "_graph"
295+
296+
options, collections := newGraphOpts(db)
297+
298+
options.IsDisjoint = true
299+
300+
g, err := db.CreateGraph(ctx, graphID, &options)
301+
require.NoError(t, err)
302+
303+
// Wait for collections to be created
304+
waitForCollections(t, db, collections)
305+
306+
graphs, err := db.Graphs(ctx)
307+
require.NoError(t, err)
308+
require.Len(t, graphs, 1)
309+
310+
require.Equal(t, g.Name(), graphs[0].Name())
311+
require.True(t, graphs[0].IsDisjoint())
312+
})
313+
}

0 commit comments

Comments
 (0)