From 2d96a7865c7c445f96b6596835b9d7b700af7f2c Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 31 Aug 2021 22:03:09 +0000 Subject: [PATCH 1/3] [Feature] Query ForceOneShardAttributeValue --- query.go | 34 ++++++++++++++++++++++++---------- test/query_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/query.go b/query.go index 5b5358c4..083b9374 100644 --- a/query.go +++ b/query.go @@ -28,16 +28,17 @@ import ( ) const ( - keyQueryCount = "arangodb-query-count" - keyQueryBatchSize = "arangodb-query-batchSize" - keyQueryCache = "arangodb-query-cache" - keyQueryMemoryLimit = "arangodb-query-memoryLimit" - keyQueryTTL = "arangodb-query-ttl" - keyQueryOptSatSyncWait = "arangodb-query-opt-satSyncWait" - keyQueryOptFullCount = "arangodb-query-opt-fullCount" - keyQueryOptStream = "arangodb-query-opt-stream" - keyQueryOptProfile = "arangodb-query-opt-profile" - keyQueryOptMaxRuntime = "arangodb-query-opt-maxRuntime" + keyQueryCount = "arangodb-query-count" + keyQueryBatchSize = "arangodb-query-batchSize" + keyQueryCache = "arangodb-query-cache" + keyQueryMemoryLimit = "arangodb-query-memoryLimit" + keyQueryForceOneShardAttributeValue = "arangodb-query-ForceOneShardAttributeValue" + keyQueryTTL = "arangodb-query-ttl" + keyQueryOptSatSyncWait = "arangodb-query-opt-satSyncWait" + keyQueryOptFullCount = "arangodb-query-opt-fullCount" + keyQueryOptStream = "arangodb-query-opt-stream" + keyQueryOptProfile = "arangodb-query-opt-profile" + keyQueryOptMaxRuntime = "arangodb-query-opt-maxRuntime" ) // WithQueryCount is used to configure a context that will set the Count of a query request, @@ -70,6 +71,11 @@ func WithQueryMemoryLimit(parent context.Context, value int64) context.Context { return context.WithValue(contextOrBackground(parent), keyQueryMemoryLimit, value) } +// WithQueryForceOneShardAttributeValue is used to configure a context that will set the ForceOneShardAttributeValue of a query request, +func WithQueryForceOneShardAttributeValue(parent context.Context, value string) context.Context { + return context.WithValue(contextOrBackground(parent), keyQueryForceOneShardAttributeValue, value) +} + // WithQueryTTL is used to configure a context that will set the TTL of a query request, func WithQueryTTL(parent context.Context, value time.Duration) context.Context { return context.WithValue(contextOrBackground(parent), keyQueryTTL, value) @@ -146,6 +152,9 @@ type queryRequest struct { // amount of time. This is useful to ensure garbage collection of cursors that are not fully fetched by clients. // If not set, a server-defined value will be used. TTL float64 `json:"ttl,omitempty"` + // ForceOneShardAttributeValue This query option can be used in complex queries in case the query optimizer cannot + // automatically detect that the query can be limited to only a single server (e.g. in a disjoint smart graph case). + ForceOneShardAttributeValue *string `json:"forceOneShardAttributeValue,omitempty"` // contains the query string to be executed Query string `json:"query"` // key/value pairs representing the bind parameters. @@ -207,6 +216,11 @@ func (q *queryRequest) applyContextSettings(ctx context.Context) { q.MemoryLimit = value } } + if rawValue := ctx.Value(keyQueryForceOneShardAttributeValue); rawValue != nil { + if value, ok := rawValue.(string); ok { + q.ForceOneShardAttributeValue = &value + } + } if rawValue := ctx.Value(keyQueryTTL); rawValue != nil { if value, ok := rawValue.(time.Duration); ok { q.TTL = value.Seconds() diff --git a/test/query_test.go b/test/query_test.go index bf60e0f0..cf6dcfef 100644 --- a/test/query_test.go +++ b/test/query_test.go @@ -229,3 +229,41 @@ func TestProfileQuery(t *testing.T) { } }) } + +// TestForceOneShardAttributeValue test ForceOneShardAttributeValue query attribute. +func TestForceOneShardAttributeValue(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + c := createClientFromEnv(t, true) + + EnsureVersion(t, ctx, c).CheckVersion(MinimumVersion("3.9.0")).Cluster().Enterprise() + + db := ensureDatabase(ctx, c, "force_one_shard_attribute_value", nil, t) + + db, clean := prepareQueryDatabase(t, ctx, c, "force_one_shard_attribute_value") + defer clean(t) + + // Setup tests + tests := []profileQueryTest{ + { + Query: "FOR d IN books SORT d.Title RETURN d", + }, + { + Query: "FOR d IN books FILTER d.Title==@title SORT d.Title RETURN d", + BindVars: map[string]interface{}{ + "title": "Book 16", + }, + }, + } + + t.Run("With ForceOneShardAttributeValue", func(t *testing.T) { + for i, test := range tests { + t.Run(fmt.Sprintf("Run %d", i), func(t *testing.T) { + nCtx := driver.WithQueryForceOneShardAttributeValue(ctx, "value") + _, err := db.Query(nCtx, test.Query, test.BindVars) + require.NoError(t, err) + }) + } + }) +} From ca16901e3719dbaaefbf161809c3915aebab1a8e Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 7 Sep 2021 19:48:36 +0000 Subject: [PATCH 2/3] RV --- query.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query.go b/query.go index 083b9374..879b181e 100644 --- a/query.go +++ b/query.go @@ -32,7 +32,7 @@ const ( keyQueryBatchSize = "arangodb-query-batchSize" keyQueryCache = "arangodb-query-cache" keyQueryMemoryLimit = "arangodb-query-memoryLimit" - keyQueryForceOneShardAttributeValue = "arangodb-query-ForceOneShardAttributeValue" + keyQueryForceOneShardAttributeValue = "arangodb-query-forceOneShardAttributeValue" keyQueryTTL = "arangodb-query-ttl" keyQueryOptSatSyncWait = "arangodb-query-opt-satSyncWait" keyQueryOptFullCount = "arangodb-query-opt-fullCount" From e3d2176614e10aee936818e8f731934097ef34a7 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Wed, 15 Sep 2021 20:31:33 +0000 Subject: [PATCH 3/3] Move flag under options --- query.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/query.go b/query.go index 879b181e..4097bdec 100644 --- a/query.go +++ b/query.go @@ -152,9 +152,6 @@ type queryRequest struct { // amount of time. This is useful to ensure garbage collection of cursors that are not fully fetched by clients. // If not set, a server-defined value will be used. TTL float64 `json:"ttl,omitempty"` - // ForceOneShardAttributeValue This query option can be used in complex queries in case the query optimizer cannot - // automatically detect that the query can be limited to only a single server (e.g. in a disjoint smart graph case). - ForceOneShardAttributeValue *string `json:"forceOneShardAttributeValue,omitempty"` // contains the query string to be executed Query string `json:"query"` // key/value pairs representing the bind parameters. @@ -188,6 +185,9 @@ type queryRequest struct { // MaxRuntime specify the timeout which can be used to kill a query on the server after the specified // amount in time. The timeout value is specified in seconds. A value of 0 means no timeout will be enforced. MaxRuntime float64 `json:"maxRuntime,omitempty"` + // ForceOneShardAttributeValue This query option can be used in complex queries in case the query optimizer cannot + // automatically detect that the query can be limited to only a single server (e.g. in a disjoint smart graph case). + ForceOneShardAttributeValue *string `json:"forceOneShardAttributeValue,omitempty"` } `json:"options,omitempty"` } @@ -218,7 +218,7 @@ func (q *queryRequest) applyContextSettings(ctx context.Context) { } if rawValue := ctx.Value(keyQueryForceOneShardAttributeValue); rawValue != nil { if value, ok := rawValue.(string); ok { - q.ForceOneShardAttributeValue = &value + q.Options.ForceOneShardAttributeValue = &value } } if rawValue := ctx.Value(keyQueryTTL); rawValue != nil {