From 1f1b34aa077932d4ea3999934cd78b95f6a88907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Kmie=C4=87?= Date: Thu, 20 Feb 2025 10:15:34 +0000 Subject: [PATCH 1/2] Deprecated EnsureAnalyzer for EnsureCreatedAnalyzer with signature common to all other Ensure* funcitons --- Makefile | 7 ---- database_arangosearch_analyzers.go | 5 +++ database_arangosearch_analyzers_impl.go | 36 +++++++++++++++++++++ v2/arangodb/collection_indexes_impl.go | 28 ++++++++-------- v2/arangodb/database_analyzer.go | 5 +++ v2/arangodb/database_analyzer_impl.go | 23 +++++++++++++ v2/tests/database_analyzer_test.go | 6 ++-- v2/tests/database_view-arangosearch_test.go | 4 +-- 8 files changed, 88 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 5b7cb399..ccaae80f 100644 --- a/Makefile +++ b/Makefile @@ -80,13 +80,6 @@ endif TEST_NET := --net=host -# Installation of jq is required for processing AGENCY_DUMP -# ifdef DUMP_AGENCY_ON_FAILURE -# CHECK_JQ_INSTALLTION := $(shell command -v jq >/dev/null 2>&1 || ( -# -# endif - - # By default we run tests against single endpoint to avoid problems with data propagation in Cluster mode # e.g. when we create a document in one endpoint, it may not be visible in another endpoint for a while TEST_ENDPOINTS := http://localhost:7001 diff --git a/database_arangosearch_analyzers.go b/database_arangosearch_analyzers.go index c2fa463f..e7780e43 100644 --- a/database_arangosearch_analyzers.go +++ b/database_arangosearch_analyzers.go @@ -49,10 +49,15 @@ type ArangoSearchAnalyzer interface { type DatabaseArangoSearchAnalyzers interface { + // Deprecated: Use EnsureCreatedAnalyzer instead // Ensure ensures that the given analyzer exists. If it does not exist it is created. // The function returns whether the analyzer already existed or an error. EnsureAnalyzer(ctx context.Context, analyzer ArangoSearchAnalyzerDefinition) (bool, ArangoSearchAnalyzer, error) + // EnsureCreatedAnalyzer creates an Analyzer for the database, if it does not already exist. + // The function returns the Analyser object together with a boolean indicating if the Analyzer was newly created (true) or pre-existing (false). + EnsureCreatedAnalyzer(ctx context.Context, analyzer *ArangoSearchAnalyzerDefinition) (ArangoSearchAnalyzer, bool, error) + // Get returns the analyzer definition for the given analyzer or returns an error Analyzer(ctx context.Context, name string) (ArangoSearchAnalyzer, error) diff --git a/database_arangosearch_analyzers_impl.go b/database_arangosearch_analyzers_impl.go index e6f7e93c..eeed4bd5 100644 --- a/database_arangosearch_analyzers_impl.go +++ b/database_arangosearch_analyzers_impl.go @@ -24,6 +24,7 @@ package driver import ( "context" + "net/http" "path" "strings" ) @@ -90,6 +91,7 @@ func (a *analyzer) Database() Database { return a.db } +// Deprecated: Use EnsureCreatedAnalyzer instead // Ensure ensures that the given analyzer exists. If it does not exist it is created. // The function returns whether the analyzer already existed or an error. func (d *database) EnsureAnalyzer(ctx context.Context, definition ArangoSearchAnalyzerDefinition) (bool, ArangoSearchAnalyzer, error) { @@ -120,6 +122,40 @@ func (d *database) EnsureAnalyzer(ctx context.Context, definition ArangoSearchAn }, nil } +// EnsureCreatedAnalyzer creates an Analyzer for the database, if it does not already exist. +// The function returns the Analyser object together with a boolean indicating if the Analyzer was newly created (true) or pre-existing (false). +func (d *database) EnsureCreatedAnalyzer(ctx context.Context, definition *ArangoSearchAnalyzerDefinition) (ArangoSearchAnalyzer, bool, error) { + req, err := d.conn.NewRequest("POST", path.Join(d.relPath(), "_api/analyzer")) + if err != nil { + return nil, false, WithStack(err) + } + applyContextSettings(ctx, req) + req, err = req.SetBody(definition) + if err != nil { + return nil, false, WithStack(err) + } + resp, err := d.conn.Do(ctx, req) + if err != nil { + return nil, false, WithStack(err) + } + + if err := resp.CheckStatus(http.StatusCreated, http.StatusOK); err != nil { + return nil, false, WithStack(err) + } + + var actualDef ArangoSearchAnalyzerDefinition + if err := resp.ParseBody("", &actualDef); err != nil { + return nil, false, WithStack(err) + } + + created := resp.StatusCode() == http.StatusCreated + return &analyzer{ + db: d, + definition: actualDef, + }, created, nil + +} + // Get returns the analyzer definition for the given analyzer or returns an error func (d *database) Analyzer(ctx context.Context, name string) (ArangoSearchAnalyzer, error) { req, err := d.conn.NewRequest("GET", path.Join(d.relPath(), "_api/analyzer/", name)) diff --git a/v2/arangodb/collection_indexes_impl.go b/v2/arangodb/collection_indexes_impl.go index 7ec72804..8d0e5a67 100644 --- a/v2/arangodb/collection_indexes_impl.go +++ b/v2/arangodb/collection_indexes_impl.go @@ -121,8 +121,8 @@ func (c *collectionIndexes) EnsurePersistentIndex(ctx context.Context, fields [] } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureGeoIndex(ctx context.Context, fields []string, options *CreateGeoIndexOptions) (IndexResponse, bool, error) { @@ -137,8 +137,8 @@ func (c *collectionIndexes) EnsureGeoIndex(ctx context.Context, fields []string, } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureTTLIndex(ctx context.Context, fields []string, expireAfter int, options *CreateTTLIndexOptions) (IndexResponse, bool, error) { @@ -155,8 +155,8 @@ func (c *collectionIndexes) EnsureTTLIndex(ctx context.Context, fields []string, } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureZKDIndex(ctx context.Context, fields []string, options *CreateZKDIndexOptions) (IndexResponse, bool, error) { @@ -171,8 +171,8 @@ func (c *collectionIndexes) EnsureZKDIndex(ctx context.Context, fields []string, } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureMDIIndex(ctx context.Context, fields []string, options *CreateMDIIndexOptions) (IndexResponse, bool, error) { @@ -187,8 +187,8 @@ func (c *collectionIndexes) EnsureMDIIndex(ctx context.Context, fields []string, } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureMDIPrefixedIndex(ctx context.Context, fields []string, options *CreateMDIPrefixedIndexOptions) (IndexResponse, bool, error) { @@ -203,8 +203,8 @@ func (c *collectionIndexes) EnsureMDIPrefixedIndex(ctx context.Context, fields [ } result := responseIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newIndexResponse(&result), created, err } func (c *collectionIndexes) EnsureInvertedIndex(ctx context.Context, options *InvertedIndexOptions) (IndexResponse, bool, error) { @@ -221,8 +221,8 @@ func (c *collectionIndexes) EnsureInvertedIndex(ctx context.Context, options *In } result := responseInvertedIndex{} - exist, err := c.ensureIndex(ctx, &reqData, &result) - return newInvertedIndexResponse(&result), exist, err + created, err := c.ensureIndex(ctx, &reqData, &result) + return newInvertedIndexResponse(&result), created, err } func (c *collectionIndexes) ensureIndex(ctx context.Context, reqData interface{}, result interface{}) (bool, error) { diff --git a/v2/arangodb/database_analyzer.go b/v2/arangodb/database_analyzer.go index ba3f8948..a016af69 100644 --- a/v2/arangodb/database_analyzer.go +++ b/v2/arangodb/database_analyzer.go @@ -25,10 +25,15 @@ import ( ) type DatabaseAnalyzer interface { + // Deprecated: Use EnsureCreatedAnalyzer instead // EnsureAnalyzer ensures that the given analyzer exists. If it does not exist, it is created. // The function returns whether the analyzer already existed or not. EnsureAnalyzer(ctx context.Context, analyzer *AnalyzerDefinition) (bool, Analyzer, error) + // EnsureCreatedAnalyzer creates an Analyzer for the database, if it does not already exist. + // It returns the Analyser object together with a boolean indicating if the Analyzer was newly created (true) or pre-existing (false). + EnsureCreatedAnalyzer(ctx context.Context, analyzer *AnalyzerDefinition) (Analyzer, bool, error) + // Analyzer returns the analyzer definition for the given analyzer Analyzer(ctx context.Context, name string) (Analyzer, error) diff --git a/v2/arangodb/database_analyzer_impl.go b/v2/arangodb/database_analyzer_impl.go index 9b93479d..7dc11370 100644 --- a/v2/arangodb/database_analyzer_impl.go +++ b/v2/arangodb/database_analyzer_impl.go @@ -44,6 +44,7 @@ type databaseAnalyzer struct { db *database } +// Deprecated: Use EnsureCreatedAnalyzer instead func (d databaseAnalyzer) EnsureAnalyzer(ctx context.Context, analyzer *AnalyzerDefinition) (bool, Analyzer, error) { urlEndpoint := d.db.url("_api", "analyzer") @@ -64,6 +65,28 @@ func (d databaseAnalyzer) EnsureAnalyzer(ctx context.Context, analyzer *Analyzer } } +// EnsureCreatedAnalyzer creates an Analyzer for the database, if it does not already exist. +// It returns the Analyser object together with a boolean indicating if the Analyzer was newly created (true) or pre-existing (false). +func (d databaseAnalyzer) EnsureCreatedAnalyzer(ctx context.Context, analyzer *AnalyzerDefinition) (Analyzer, bool, error) { + urlEndpoint := d.db.url("_api", "analyzer") + + var response struct { + shared.ResponseStruct `json:",inline"` + AnalyzerDefinition + } + resp, err := connection.CallPost(ctx, d.db.connection(), urlEndpoint, &response, analyzer) + if err != nil { + return nil, false, errors.WithStack(err) + } + + switch code := resp.Code(); code { + case http.StatusCreated, http.StatusOK: + return newAnalyzer(d.db, response.AnalyzerDefinition), code == http.StatusCreated, nil + default: + return nil, false, response.AsArangoErrorWithCode(code) + } +} + func (d databaseAnalyzer) Analyzer(ctx context.Context, name string) (Analyzer, error) { urlEndpoint := d.db.url("_api", "analyzer", url.PathEscape(name)) diff --git a/v2/tests/database_analyzer_test.go b/v2/tests/database_analyzer_test.go index 4c852d45..21113e08 100644 --- a/v2/tests/database_analyzer_test.go +++ b/v2/tests/database_analyzer_test.go @@ -362,7 +362,7 @@ func Test_Analyzers(t *testing.T) { skipNoEnterprise(client, ctx, t) } - existed, ensuredA, err := db.EnsureAnalyzer(ctx, &testCase.Definition) + ensuredA, created, err := db.EnsureCreatedAnalyzer(ctx, &testCase.Definition) if testCase.HasError { require.Error(t, err) @@ -370,7 +370,7 @@ func Test_Analyzers(t *testing.T) { require.NoError(t, err) } - require.Equal(t, testCase.Found, existed) + require.NotEqual(t, testCase.Found, created) if ensuredA != nil { var def arangodb.AnalyzerDefinition if testCase.ExpectedDefinition != nil { @@ -417,7 +417,7 @@ func Test_AnalyzerRemove(t *testing.T) { WithDatabase(t, client, nil, func(db arangodb.Database) { ctx := context.Background() - _, a, err := db.EnsureAnalyzer(ctx, &def) + a, _, err := db.EnsureCreatedAnalyzer(ctx, &def) require.NoError(t, err) // delete and check it was deleted (use force to delete it even if it is in use) diff --git a/v2/tests/database_view-arangosearch_test.go b/v2/tests/database_view-arangosearch_test.go index 7852a5e5..c9e69cb9 100644 --- a/v2/tests/database_view-arangosearch_test.go +++ b/v2/tests/database_view-arangosearch_test.go @@ -612,9 +612,9 @@ func Test_UseArangoSearchViewWithPipelineAnalyzer(t *testing.T) { arangodb.ArangoSearchFeatureNorm, }, } - existed, _, err := db.EnsureAnalyzer(ctx, &analyzer) + _, created, err := db.EnsureCreatedAnalyzer(ctx, &analyzer) require.NoError(t, err) - require.False(t, existed) + require.True(t, created) ensureArangoSearchView(ctx, db, "some_view_with_analyzer", &arangodb.ArangoSearchViewProperties{ Links: arangodb.ArangoSearchLinks{ From ee038d2f3bae7452d351bc402497de09e516bfbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Kmie=C4=87?= Date: Thu, 20 Feb 2025 11:32:02 +0000 Subject: [PATCH 2/2] Found is not opposite of Create. Both are false when there is an error --- v2/tests/database_analyzer_test.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/v2/tests/database_analyzer_test.go b/v2/tests/database_analyzer_test.go index 21113e08..f3bd6dd1 100644 --- a/v2/tests/database_analyzer_test.go +++ b/v2/tests/database_analyzer_test.go @@ -38,7 +38,7 @@ func Test_Analyzers(t *testing.T) { MinVersion *arangodb.Version Definition arangodb.AnalyzerDefinition ExpectedDefinition *arangodb.AnalyzerDefinition - Found bool + Created bool HasError bool EnterpriseOnly bool }{ @@ -48,6 +48,7 @@ func Test_Analyzers(t *testing.T) { Name: "my-identitfy", Type: arangodb.ArangoSearchAnalyzerTypeIdentity, }, + Created: true, }, { Name: "create-again-my-identity", @@ -55,7 +56,7 @@ func Test_Analyzers(t *testing.T) { Name: "my-identitfy", Type: arangodb.ArangoSearchAnalyzerTypeIdentity, }, - Found: true, + Created: false, }, { Name: "create-again-my-identity-diff-type", @@ -66,6 +67,7 @@ func Test_Analyzers(t *testing.T) { Delimiter: "äöü", }, }, + Created: false, HasError: true, }, { @@ -78,6 +80,7 @@ func Test_Analyzers(t *testing.T) { Delimiters: []string{"ö", "ü"}, }, }, + Created: true, HasError: false, }, { @@ -89,6 +92,7 @@ func Test_Analyzers(t *testing.T) { Delimiter: "äöü", }, }, + Created: true, }, { Name: "create-my-ngram-3.6", @@ -116,6 +120,7 @@ func Test_Analyzers(t *testing.T) { StreamType: utils.NewType(arangodb.ArangoSearchNGramStreamBinary), }, }, + Created: true, }, { Name: "create-my-ngram-3.6-custom", @@ -132,6 +137,7 @@ func Test_Analyzers(t *testing.T) { StreamType: utils.NewType(arangodb.ArangoSearchNGramStreamUTF8), }, }, + Created: true, }, { Name: "create-pipeline-analyzer", @@ -155,6 +161,7 @@ func Test_Analyzers(t *testing.T) { }, }, }, + Created: true, }, { Name: "create-aql-analyzer", @@ -171,6 +178,7 @@ func Test_Analyzers(t *testing.T) { MemoryLimit: utils.NewType(1024 * 1024), }, }, + Created: true, }, { Name: "create-geopoint", @@ -188,6 +196,7 @@ func Test_Analyzers(t *testing.T) { Longitude: []string{}, }, }, + Created: true, }, { Name: "create-geojson", @@ -204,6 +213,7 @@ func Test_Analyzers(t *testing.T) { Type: arangodb.ArangoSearchAnalyzerGeoJSONTypeShape.New(), }, }, + Created: true, }, { Name: "create-geo_s2", @@ -234,6 +244,7 @@ func Test_Analyzers(t *testing.T) { Type: arangodb.ArangoSearchAnalyzerGeoJSONTypeShape.New(), }, }, + Created: true, EnterpriseOnly: true, }, { @@ -247,6 +258,7 @@ func Test_Analyzers(t *testing.T) { Case: arangodb.ArangoSearchCaseUpper, }, }, + Created: true, }, { Name: "create-collation", @@ -265,6 +277,7 @@ func Test_Analyzers(t *testing.T) { Locale: "en_US", }, }, + Created: true, }, { Name: "create-stopWords", @@ -291,6 +304,7 @@ func Test_Analyzers(t *testing.T) { }, }, }, + Created: true, }, { Name: "my-minhash", @@ -330,6 +344,7 @@ func Test_Analyzers(t *testing.T) { NumHashes: utils.NewType[uint64](2), }, }, + Created: true, }, { Name: "create-my-wildcard", @@ -342,6 +357,7 @@ func Test_Analyzers(t *testing.T) { }, }, HasError: false, + Created: true, }, } @@ -370,7 +386,7 @@ func Test_Analyzers(t *testing.T) { require.NoError(t, err) } - require.NotEqual(t, testCase.Found, created) + require.Equal(t, testCase.Created, created) if ensuredA != nil { var def arangodb.AnalyzerDefinition if testCase.ExpectedDefinition != nil {