diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Clients/AbtestingClient.cs b/clients/algoliasearch-client-csharp/algoliasearch/Clients/AbtestingClient.cs
index adcffef9376..27f6e704f49 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Clients/AbtestingClient.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Clients/AbtestingClient.cs
@@ -189,6 +189,36 @@ public interface IAbtestingClient
/// ABTestResponse
ABTestResponse DeleteABTest(int id, RequestOptions options = null, CancellationToken cancellationToken = default);
+ ///
+ /// Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ ///
+ ///
+ /// Required API Key ACLs:
+ /// - analytics
+ ///
+ /// Add extra http header or query parameters to Algolia.
+ /// Cancellation Token to cancel the request.
+ /// Thrown when arguments are not correct
+ /// Thrown when the API call was rejected by Algolia
+ /// Thrown when the client failed to call the endpoint
+ /// Task of EstimateABTestResponse
+ Task EstimateABTestAsync(EstimateABTestRequest estimateABTestRequest, RequestOptions options = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic. (Synchronous version)
+ ///
+ ///
+ /// Required API Key ACLs:
+ /// - analytics
+ ///
+ /// Add extra http header or query parameters to Algolia.
+ /// Cancellation Token to cancel the request.
+ /// Thrown when arguments are not correct
+ /// Thrown when the API call was rejected by Algolia
+ /// Thrown when the client failed to call the endpoint
+ /// EstimateABTestResponse
+ EstimateABTestResponse EstimateABTest(EstimateABTestRequest estimateABTestRequest, RequestOptions options = null, CancellationToken cancellationToken = default);
+
///
/// Retrieves the details for an A/B test by its ID.
///
@@ -513,6 +543,26 @@ public ABTestResponse DeleteABTest(int id, RequestOptions options = null, Cancel
AsyncHelper.RunSync(() => DeleteABTestAsync(id, options, cancellationToken));
+ ///
+ public async Task EstimateABTestAsync(EstimateABTestRequest estimateABTestRequest, RequestOptions options = null, CancellationToken cancellationToken = default)
+ {
+
+ if (estimateABTestRequest == null)
+ throw new ArgumentException("Parameter `estimateABTestRequest` is required when calling `EstimateABTest`.");
+
+ var requestOptions = new InternalRequestOptions(options);
+
+
+ requestOptions.Data = estimateABTestRequest;
+ return await _transport.ExecuteRequestAsync(new HttpMethod("POST"), "/2/abtests/estimate", requestOptions, cancellationToken).ConfigureAwait(false);
+ }
+
+
+ ///
+ public EstimateABTestResponse EstimateABTest(EstimateABTestRequest estimateABTestRequest, RequestOptions options = null, CancellationToken cancellationToken = default) =>
+ AsyncHelper.RunSync(() => EstimateABTestAsync(estimateABTestRequest, options, cancellationToken));
+
+
///
public async Task GetABTestAsync(int id, RequestOptions options = null, CancellationToken cancellationToken = default)
{
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/Effect.cs b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EffectMetric.cs
similarity index 92%
rename from clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/Effect.cs
rename to clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EffectMetric.cs
index 4a367e65d2d..6606fefcd97 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/Effect.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EffectMetric.cs
@@ -15,8 +15,8 @@ namespace Algolia.Search.Models.Abtesting;
/// Metric for which you want to detect the smallest relative difference.
///
/// Metric for which you want to detect the smallest relative difference.
-[JsonConverter(typeof(Serializer.JsonStringEnumConverter))]
-public enum Effect
+[JsonConverter(typeof(Serializer.JsonStringEnumConverter))]
+public enum EffectMetric
{
///
/// Enum AddToCartRate for value: addToCartRate
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestRequest.cs b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestRequest.cs
new file mode 100644
index 00000000000..7678a10ff8e
--- /dev/null
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestRequest.cs
@@ -0,0 +1,110 @@
+//
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+//
+using System;
+using System.Text;
+using System.Linq;
+using System.Text.Json.Serialization;
+using System.Collections.Generic;
+using Algolia.Search.Serializer;
+using System.Text.Json;
+
+namespace Algolia.Search.Models.Abtesting;
+
+///
+/// EstimateABTestRequest
+///
+public partial class EstimateABTestRequest
+{
+ ///
+ /// Initializes a new instance of the EstimateABTestRequest class.
+ ///
+ [JsonConstructor]
+ public EstimateABTestRequest() { }
+ ///
+ /// Initializes a new instance of the EstimateABTestRequest class.
+ ///
+ /// configuration (required).
+ /// A/B test variants. (required).
+ public EstimateABTestRequest(EstimateConfiguration configuration, List variants)
+ {
+ Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
+ Variants = variants ?? throw new ArgumentNullException(nameof(variants));
+ }
+
+ ///
+ /// Gets or Sets Configuration
+ ///
+ [JsonPropertyName("configuration")]
+ public EstimateConfiguration Configuration { get; set; }
+
+ ///
+ /// A/B test variants.
+ ///
+ /// A/B test variants.
+ [JsonPropertyName("variants")]
+ public List Variants { get; set; }
+
+ ///
+ /// Returns the string presentation of the object
+ ///
+ /// String presentation of the object
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("class EstimateABTestRequest {\n");
+ sb.Append(" Configuration: ").Append(Configuration).Append("\n");
+ sb.Append(" Variants: ").Append(Variants).Append("\n");
+ sb.Append("}\n");
+ return sb.ToString();
+ }
+
+ ///
+ /// Returns the JSON string presentation of the object
+ ///
+ /// JSON string presentation of the object
+ public virtual string ToJson()
+ {
+ return JsonSerializer.Serialize(this, JsonConfig.Options);
+ }
+
+ ///
+ /// Returns true if objects are equal
+ ///
+ /// Object to be compared
+ /// Boolean
+ public override bool Equals(object obj)
+ {
+ if (obj is not EstimateABTestRequest input)
+ {
+ return false;
+ }
+
+ return
+ (Configuration == input.Configuration || (Configuration != null && Configuration.Equals(input.Configuration))) &&
+ (Variants == input.Variants || Variants != null && input.Variants != null && Variants.SequenceEqual(input.Variants));
+ }
+
+ ///
+ /// Gets the hash code
+ ///
+ /// Hash code
+ public override int GetHashCode()
+ {
+ unchecked // Overflow is fine, just wrap
+ {
+ int hashCode = 41;
+ if (Configuration != null)
+ {
+ hashCode = (hashCode * 59) + Configuration.GetHashCode();
+ }
+ if (Variants != null)
+ {
+ hashCode = (hashCode * 59) + Variants.GetHashCode();
+ }
+ return hashCode;
+ }
+ }
+
+}
+
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestResponse.cs b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestResponse.cs
new file mode 100644
index 00000000000..5f7d7e7ed64
--- /dev/null
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateABTestResponse.cs
@@ -0,0 +1,106 @@
+//
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+//
+using System;
+using System.Text;
+using System.Linq;
+using System.Text.Json.Serialization;
+using System.Collections.Generic;
+using Algolia.Search.Serializer;
+using System.Text.Json;
+
+namespace Algolia.Search.Models.Abtesting;
+
+///
+/// EstimateABTestResponse
+///
+public partial class EstimateABTestResponse
+{
+ ///
+ /// Initializes a new instance of the EstimateABTestResponse class.
+ ///
+ public EstimateABTestResponse()
+ {
+ }
+
+ ///
+ /// Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ ///
+ /// Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ [JsonPropertyName("durationDays")]
+ public long? DurationDays { get; set; }
+
+ ///
+ /// Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ ///
+ /// Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ [JsonPropertyName("controlSampleSize")]
+ public long? ControlSampleSize { get; set; }
+
+ ///
+ /// Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ ///
+ /// Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ [JsonPropertyName("experimentSampleSize")]
+ public long? ExperimentSampleSize { get; set; }
+
+ ///
+ /// Returns the string presentation of the object
+ ///
+ /// String presentation of the object
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("class EstimateABTestResponse {\n");
+ sb.Append(" DurationDays: ").Append(DurationDays).Append("\n");
+ sb.Append(" ControlSampleSize: ").Append(ControlSampleSize).Append("\n");
+ sb.Append(" ExperimentSampleSize: ").Append(ExperimentSampleSize).Append("\n");
+ sb.Append("}\n");
+ return sb.ToString();
+ }
+
+ ///
+ /// Returns the JSON string presentation of the object
+ ///
+ /// JSON string presentation of the object
+ public virtual string ToJson()
+ {
+ return JsonSerializer.Serialize(this, JsonConfig.Options);
+ }
+
+ ///
+ /// Returns true if objects are equal
+ ///
+ /// Object to be compared
+ /// Boolean
+ public override bool Equals(object obj)
+ {
+ if (obj is not EstimateABTestResponse input)
+ {
+ return false;
+ }
+
+ return
+ (DurationDays == input.DurationDays || DurationDays.Equals(input.DurationDays)) &&
+ (ControlSampleSize == input.ControlSampleSize || ControlSampleSize.Equals(input.ControlSampleSize)) &&
+ (ExperimentSampleSize == input.ExperimentSampleSize || ExperimentSampleSize.Equals(input.ExperimentSampleSize));
+ }
+
+ ///
+ /// Gets the hash code
+ ///
+ /// Hash code
+ public override int GetHashCode()
+ {
+ unchecked // Overflow is fine, just wrap
+ {
+ int hashCode = 41;
+ hashCode = (hashCode * 59) + DurationDays.GetHashCode();
+ hashCode = (hashCode * 59) + ControlSampleSize.GetHashCode();
+ hashCode = (hashCode * 59) + ExperimentSampleSize.GetHashCode();
+ return hashCode;
+ }
+ }
+
+}
+
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateConfiguration.cs b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateConfiguration.cs
new file mode 100644
index 00000000000..5093dbf59a9
--- /dev/null
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/EstimateConfiguration.cs
@@ -0,0 +1,119 @@
+//
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+//
+using System;
+using System.Text;
+using System.Linq;
+using System.Text.Json.Serialization;
+using System.Collections.Generic;
+using Algolia.Search.Serializer;
+using System.Text.Json;
+
+namespace Algolia.Search.Models.Abtesting;
+
+///
+/// A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+///
+public partial class EstimateConfiguration
+{
+ ///
+ /// Initializes a new instance of the EstimateConfiguration class.
+ ///
+ [JsonConstructor]
+ public EstimateConfiguration() { }
+ ///
+ /// Initializes a new instance of the EstimateConfiguration class.
+ ///
+ /// minimumDetectableEffect (required).
+ public EstimateConfiguration(MinimumDetectableEffect minimumDetectableEffect)
+ {
+ MinimumDetectableEffect = minimumDetectableEffect ?? throw new ArgumentNullException(nameof(minimumDetectableEffect));
+ }
+
+ ///
+ /// Gets or Sets Outliers
+ ///
+ [JsonPropertyName("outliers")]
+ public Outliers Outliers { get; set; }
+
+ ///
+ /// Gets or Sets EmptySearch
+ ///
+ [JsonPropertyName("emptySearch")]
+ public EmptySearch EmptySearch { get; set; }
+
+ ///
+ /// Gets or Sets MinimumDetectableEffect
+ ///
+ [JsonPropertyName("minimumDetectableEffect")]
+ public MinimumDetectableEffect MinimumDetectableEffect { get; set; }
+
+ ///
+ /// Returns the string presentation of the object
+ ///
+ /// String presentation of the object
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("class EstimateConfiguration {\n");
+ sb.Append(" Outliers: ").Append(Outliers).Append("\n");
+ sb.Append(" EmptySearch: ").Append(EmptySearch).Append("\n");
+ sb.Append(" MinimumDetectableEffect: ").Append(MinimumDetectableEffect).Append("\n");
+ sb.Append("}\n");
+ return sb.ToString();
+ }
+
+ ///
+ /// Returns the JSON string presentation of the object
+ ///
+ /// JSON string presentation of the object
+ public virtual string ToJson()
+ {
+ return JsonSerializer.Serialize(this, JsonConfig.Options);
+ }
+
+ ///
+ /// Returns true if objects are equal
+ ///
+ /// Object to be compared
+ /// Boolean
+ public override bool Equals(object obj)
+ {
+ if (obj is not EstimateConfiguration input)
+ {
+ return false;
+ }
+
+ return
+ (Outliers == input.Outliers || (Outliers != null && Outliers.Equals(input.Outliers))) &&
+ (EmptySearch == input.EmptySearch || (EmptySearch != null && EmptySearch.Equals(input.EmptySearch))) &&
+ (MinimumDetectableEffect == input.MinimumDetectableEffect || (MinimumDetectableEffect != null && MinimumDetectableEffect.Equals(input.MinimumDetectableEffect)));
+ }
+
+ ///
+ /// Gets the hash code
+ ///
+ /// Hash code
+ public override int GetHashCode()
+ {
+ unchecked // Overflow is fine, just wrap
+ {
+ int hashCode = 41;
+ if (Outliers != null)
+ {
+ hashCode = (hashCode * 59) + Outliers.GetHashCode();
+ }
+ if (EmptySearch != null)
+ {
+ hashCode = (hashCode * 59) + EmptySearch.GetHashCode();
+ }
+ if (MinimumDetectableEffect != null)
+ {
+ hashCode = (hashCode * 59) + MinimumDetectableEffect.GetHashCode();
+ }
+ return hashCode;
+ }
+ }
+
+}
+
diff --git a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/MinimumDetectableEffect.cs b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/MinimumDetectableEffect.cs
index 9bb879f74fd..2c9930351fa 100644
--- a/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/MinimumDetectableEffect.cs
+++ b/clients/algoliasearch-client-csharp/algoliasearch/Models/Abtesting/MinimumDetectableEffect.cs
@@ -18,15 +18,24 @@ public partial class MinimumDetectableEffect
{
///
- /// Gets or Sets Effect
+ /// Gets or Sets Metric
///
- [JsonPropertyName("effect")]
- public Effect? Effect { get; set; }
+ [JsonPropertyName("metric")]
+ public EffectMetric? Metric { get; set; }
///
/// Initializes a new instance of the MinimumDetectableEffect class.
///
- public MinimumDetectableEffect()
+ [JsonConstructor]
+ public MinimumDetectableEffect() { }
+ ///
+ /// Initializes a new instance of the MinimumDetectableEffect class.
+ ///
+ /// Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1. (required).
+ /// metric (required).
+ public MinimumDetectableEffect(double size, EffectMetric? metric)
{
+ Size = size;
+ Metric = metric;
}
///
@@ -34,7 +43,7 @@ public MinimumDetectableEffect()
///
/// Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
[JsonPropertyName("size")]
- public double? Size { get; set; }
+ public double Size { get; set; }
///
/// Returns the string presentation of the object
@@ -45,7 +54,7 @@ public override string ToString()
StringBuilder sb = new StringBuilder();
sb.Append("class MinimumDetectableEffect {\n");
sb.Append(" Size: ").Append(Size).Append("\n");
- sb.Append(" Effect: ").Append(Effect).Append("\n");
+ sb.Append(" Metric: ").Append(Metric).Append("\n");
sb.Append("}\n");
return sb.ToString();
}
@@ -73,7 +82,7 @@ public override bool Equals(object obj)
return
(Size == input.Size || Size.Equals(input.Size)) &&
- (Effect == input.Effect || Effect.Equals(input.Effect));
+ (Metric == input.Metric || Metric.Equals(input.Metric));
}
///
@@ -86,7 +95,7 @@ public override int GetHashCode()
{
int hashCode = 41;
hashCode = (hashCode * 59) + Size.GetHashCode();
- hashCode = (hashCode * 59) + Effect.GetHashCode();
+ hashCode = (hashCode * 59) + Metric.GetHashCode();
return hashCode;
}
}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/api_abtesting.go b/clients/algoliasearch-client-go/algolia/abtesting/api_abtesting.go
index 290b92519c2..bcf96d19c24 100644
--- a/clients/algoliasearch-client-go/algolia/abtesting/api_abtesting.go
+++ b/clients/algoliasearch-client-go/algolia/abtesting/api_abtesting.go
@@ -911,6 +911,135 @@ func (c *APIClient) DeleteABTest(r ApiDeleteABTestRequest, opts ...RequestOption
return returnValue, nil
}
+func (r *ApiEstimateABTestRequest) UnmarshalJSON(b []byte) error {
+ req := map[string]json.RawMessage{}
+ err := json.Unmarshal(b, &req)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshal request: %w", err)
+ }
+ if v, ok := req["estimateABTestRequest"]; ok {
+ err = json.Unmarshal(v, &r.estimateABTestRequest)
+ if err != nil {
+ err = json.Unmarshal(b, &r.estimateABTestRequest)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshal estimateABTestRequest: %w", err)
+ }
+ }
+ } else {
+ err = json.Unmarshal(b, &r.estimateABTestRequest)
+ if err != nil {
+ return fmt.Errorf("cannot unmarshal body parameter estimateABTestRequest: %w", err)
+ }
+ }
+
+ return nil
+}
+
+// ApiEstimateABTestRequest represents the request with all the parameters for the API call.
+type ApiEstimateABTestRequest struct {
+ estimateABTestRequest *EstimateABTestRequest
+}
+
+// NewApiEstimateABTestRequest creates an instance of the ApiEstimateABTestRequest to be used for the API call.
+func (c *APIClient) NewApiEstimateABTestRequest(estimateABTestRequest *EstimateABTestRequest) ApiEstimateABTestRequest {
+ return ApiEstimateABTestRequest{
+ estimateABTestRequest: estimateABTestRequest,
+ }
+}
+
+/*
+EstimateABTest calls the API and returns the raw response from it.
+
+ Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+ Required API Key ACLs:
+ - analytics
+
+ Request can be constructed by NewApiEstimateABTestRequest with parameters below.
+ @param estimateABTestRequest EstimateABTestRequest
+ @param opts ...RequestOption - Optional parameters for the API call
+ @return *http.Response - The raw response from the API
+ @return []byte - The raw response body from the API
+ @return error - An error if the API call fails
+*/
+func (c *APIClient) EstimateABTestWithHTTPInfo(r ApiEstimateABTestRequest, opts ...RequestOption) (*http.Response, []byte, error) {
+ requestPath := "/2/abtests/estimate"
+
+ if r.estimateABTestRequest == nil {
+ return nil, nil, reportError("Parameter `estimateABTestRequest` is required when calling `EstimateABTest`.")
+ }
+
+ conf := config{
+ context: context.Background(),
+ queryParams: url.Values{},
+ headerParams: map[string]string{},
+ }
+
+ // optional params if any
+ for _, opt := range opts {
+ opt.apply(&conf)
+ }
+
+ var postBody any
+
+ // body params
+ postBody = r.estimateABTestRequest
+ req, err := c.prepareRequest(conf.context, requestPath, http.MethodPost, postBody, conf.headerParams, conf.queryParams)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return c.callAPI(req, false)
+}
+
+/*
+EstimateABTest casts the HTTP response body to a defined struct.
+
+Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+Required API Key ACLs:
+ - analytics
+
+Request can be constructed by NewApiEstimateABTestRequest with parameters below.
+
+ @param estimateABTestRequest EstimateABTestRequest
+ @return EstimateABTestResponse
+*/
+func (c *APIClient) EstimateABTest(r ApiEstimateABTestRequest, opts ...RequestOption) (*EstimateABTestResponse, error) {
+ var returnValue *EstimateABTestResponse
+
+ res, resBody, err := c.EstimateABTestWithHTTPInfo(r, opts...)
+ if err != nil {
+ return returnValue, err
+ }
+ if res == nil {
+ return returnValue, reportError("res is nil")
+ }
+
+ if res.StatusCode >= 300 {
+ newErr := &APIError{
+ Message: string(resBody),
+ Status: res.StatusCode,
+ }
+
+ var v ErrorBase
+ err = c.decode(&v, resBody)
+ if err != nil {
+ newErr.Message = err.Error()
+ return returnValue, newErr
+ }
+
+ return returnValue, newErr
+ }
+
+ err = c.decode(&returnValue, resBody)
+ if err != nil {
+ return returnValue, reportError("cannot decode result: %w", err)
+ }
+
+ return returnValue, nil
+}
+
func (r *ApiGetABTestRequest) UnmarshalJSON(b []byte) error {
req := map[string]json.RawMessage{}
err := json.Unmarshal(b, &req)
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_effect.go b/clients/algoliasearch-client-go/algolia/abtesting/model_effect.go
deleted file mode 100644
index 03965b7f6e0..00000000000
--- a/clients/algoliasearch-client-go/algolia/abtesting/model_effect.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
-package abtesting
-
-import (
- "encoding/json"
- "fmt"
-)
-
-// Effect Metric for which you want to detect the smallest relative difference.
-type Effect string
-
-// List of Effect.
-const (
- EFFECT_ADD_TO_CART_RATE Effect = "addToCartRate"
- EFFECT_CLICK_THROUGH_RATE Effect = "clickThroughRate"
- EFFECT_CONVERSION_RATE Effect = "conversionRate"
- EFFECT_PURCHASE_RATE Effect = "purchaseRate"
-)
-
-// All allowed values of Effect enum.
-var AllowedEffectEnumValues = []Effect{
- "addToCartRate",
- "clickThroughRate",
- "conversionRate",
- "purchaseRate",
-}
-
-func (v *Effect) UnmarshalJSON(src []byte) error {
- var value string
- err := json.Unmarshal(src, &value)
- if err != nil {
- return fmt.Errorf("failed to unmarshal value '%s' for enum 'Effect': %w", string(src), err)
- }
- enumTypeValue := Effect(value)
- for _, existing := range AllowedEffectEnumValues {
- if existing == enumTypeValue {
- *v = enumTypeValue
- return nil
- }
- }
-
- return fmt.Errorf("%+v is not a valid Effect", value)
-}
-
-// NewEffectFromValue returns a pointer to a valid Effect
-// for the value passed as argument, or an error if the value passed is not allowed by the enum.
-func NewEffectFromValue(v string) (*Effect, error) {
- ev := Effect(v)
- if ev.IsValid() {
- return &ev, nil
- } else {
- return nil, fmt.Errorf("invalid value '%v' for Effect: valid values are %v", v, AllowedEffectEnumValues)
- }
-}
-
-// IsValid return true if the value is valid for the enum, false otherwise.
-func (v Effect) IsValid() bool {
- for _, existing := range AllowedEffectEnumValues {
- if existing == v {
- return true
- }
- }
- return false
-}
-
-// Ptr returns reference to Effect value.
-func (v Effect) Ptr() *Effect {
- return &v
-}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_effect_metric.go b/clients/algoliasearch-client-go/algolia/abtesting/model_effect_metric.go
new file mode 100644
index 00000000000..6928a31e06a
--- /dev/null
+++ b/clients/algoliasearch-client-go/algolia/abtesting/model_effect_metric.go
@@ -0,0 +1,69 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+package abtesting
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// EffectMetric Metric for which you want to detect the smallest relative difference.
+type EffectMetric string
+
+// List of EffectMetric.
+const (
+ EFFECT_METRIC_ADD_TO_CART_RATE EffectMetric = "addToCartRate"
+ EFFECT_METRIC_CLICK_THROUGH_RATE EffectMetric = "clickThroughRate"
+ EFFECT_METRIC_CONVERSION_RATE EffectMetric = "conversionRate"
+ EFFECT_METRIC_PURCHASE_RATE EffectMetric = "purchaseRate"
+)
+
+// All allowed values of EffectMetric enum.
+var AllowedEffectMetricEnumValues = []EffectMetric{
+ "addToCartRate",
+ "clickThroughRate",
+ "conversionRate",
+ "purchaseRate",
+}
+
+func (v *EffectMetric) UnmarshalJSON(src []byte) error {
+ var value string
+ err := json.Unmarshal(src, &value)
+ if err != nil {
+ return fmt.Errorf("failed to unmarshal value '%s' for enum 'EffectMetric': %w", string(src), err)
+ }
+ enumTypeValue := EffectMetric(value)
+ for _, existing := range AllowedEffectMetricEnumValues {
+ if existing == enumTypeValue {
+ *v = enumTypeValue
+ return nil
+ }
+ }
+
+ return fmt.Errorf("%+v is not a valid EffectMetric", value)
+}
+
+// NewEffectMetricFromValue returns a pointer to a valid EffectMetric
+// for the value passed as argument, or an error if the value passed is not allowed by the enum.
+func NewEffectMetricFromValue(v string) (*EffectMetric, error) {
+ ev := EffectMetric(v)
+ if ev.IsValid() {
+ return &ev, nil
+ } else {
+ return nil, fmt.Errorf("invalid value '%v' for EffectMetric: valid values are %v", v, AllowedEffectMetricEnumValues)
+ }
+}
+
+// IsValid return true if the value is valid for the enum, false otherwise.
+func (v EffectMetric) IsValid() bool {
+ for _, existing := range AllowedEffectMetricEnumValues {
+ if existing == v {
+ return true
+ }
+ }
+ return false
+}
+
+// Ptr returns reference to EffectMetric value.
+func (v EffectMetric) Ptr() *EffectMetric {
+ return &v
+}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_request.go b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_request.go
new file mode 100644
index 00000000000..e45f3002a95
--- /dev/null
+++ b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_request.go
@@ -0,0 +1,103 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+package abtesting
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// EstimateABTestRequest struct for EstimateABTestRequest.
+type EstimateABTestRequest struct {
+ Configuration EstimateConfiguration `json:"configuration"`
+ // A/B test variants.
+ Variants []AddABTestsVariant `json:"variants"`
+}
+
+// NewEstimateABTestRequest instantiates a new EstimateABTestRequest object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed.
+func NewEstimateABTestRequest(configuration EstimateConfiguration, variants []AddABTestsVariant) *EstimateABTestRequest {
+ this := &EstimateABTestRequest{}
+ this.Configuration = configuration
+ this.Variants = variants
+ return this
+}
+
+// NewEmptyEstimateABTestRequest return a pointer to an empty EstimateABTestRequest object.
+func NewEmptyEstimateABTestRequest() *EstimateABTestRequest {
+ return &EstimateABTestRequest{}
+}
+
+// GetConfiguration returns the Configuration field value.
+func (o *EstimateABTestRequest) GetConfiguration() EstimateConfiguration {
+ if o == nil {
+ var ret EstimateConfiguration
+ return ret
+ }
+
+ return o.Configuration
+}
+
+// GetConfigurationOk returns a tuple with the Configuration field value
+// and a boolean to check if the value has been set.
+func (o *EstimateABTestRequest) GetConfigurationOk() (*EstimateConfiguration, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.Configuration, true
+}
+
+// SetConfiguration sets field value.
+func (o *EstimateABTestRequest) SetConfiguration(v *EstimateConfiguration) *EstimateABTestRequest {
+ o.Configuration = *v
+ return o
+}
+
+// GetVariants returns the Variants field value.
+func (o *EstimateABTestRequest) GetVariants() []AddABTestsVariant {
+ if o == nil {
+ var ret []AddABTestsVariant
+ return ret
+ }
+
+ return o.Variants
+}
+
+// GetVariantsOk returns a tuple with the Variants field value
+// and a boolean to check if the value has been set.
+func (o *EstimateABTestRequest) GetVariantsOk() ([]AddABTestsVariant, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return o.Variants, true
+}
+
+// SetVariants sets field value.
+func (o *EstimateABTestRequest) SetVariants(v []AddABTestsVariant) *EstimateABTestRequest {
+ o.Variants = v
+ return o
+}
+
+func (o EstimateABTestRequest) MarshalJSON() ([]byte, error) {
+ toSerialize := map[string]any{}
+ if true {
+ toSerialize["configuration"] = o.Configuration
+ }
+ if true {
+ toSerialize["variants"] = o.Variants
+ }
+ serialized, err := json.Marshal(toSerialize)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal EstimateABTestRequest: %w", err)
+ }
+
+ return serialized, nil
+}
+
+func (o EstimateABTestRequest) String() string {
+ out := ""
+ out += fmt.Sprintf(" configuration=%v\n", o.Configuration)
+ out += fmt.Sprintf(" variants=%v\n", o.Variants)
+ return fmt.Sprintf("EstimateABTestRequest {\n%s}", out)
+}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_response.go b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_response.go
new file mode 100644
index 00000000000..d6613e92c63
--- /dev/null
+++ b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_ab_test_response.go
@@ -0,0 +1,180 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+package abtesting
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// EstimateABTestResponse struct for EstimateABTestResponse.
+type EstimateABTestResponse struct {
+ // Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ DurationDays *int64 `json:"durationDays,omitempty"`
+ // Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ ControlSampleSize *int64 `json:"controlSampleSize,omitempty"`
+ // Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ ExperimentSampleSize *int64 `json:"experimentSampleSize,omitempty"`
+}
+
+type EstimateABTestResponseOption func(f *EstimateABTestResponse)
+
+func WithEstimateABTestResponseDurationDays(val int64) EstimateABTestResponseOption {
+ return func(f *EstimateABTestResponse) {
+ f.DurationDays = &val
+ }
+}
+
+func WithEstimateABTestResponseControlSampleSize(val int64) EstimateABTestResponseOption {
+ return func(f *EstimateABTestResponse) {
+ f.ControlSampleSize = &val
+ }
+}
+
+func WithEstimateABTestResponseExperimentSampleSize(val int64) EstimateABTestResponseOption {
+ return func(f *EstimateABTestResponse) {
+ f.ExperimentSampleSize = &val
+ }
+}
+
+// NewEstimateABTestResponse instantiates a new EstimateABTestResponse object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed.
+func NewEstimateABTestResponse(opts ...EstimateABTestResponseOption) *EstimateABTestResponse {
+ this := &EstimateABTestResponse{}
+ for _, opt := range opts {
+ opt(this)
+ }
+ return this
+}
+
+// NewEmptyEstimateABTestResponse return a pointer to an empty EstimateABTestResponse object.
+func NewEmptyEstimateABTestResponse() *EstimateABTestResponse {
+ return &EstimateABTestResponse{}
+}
+
+// GetDurationDays returns the DurationDays field value if set, zero value otherwise.
+func (o *EstimateABTestResponse) GetDurationDays() int64 {
+ if o == nil || o.DurationDays == nil {
+ var ret int64
+ return ret
+ }
+ return *o.DurationDays
+}
+
+// GetDurationDaysOk returns a tuple with the DurationDays field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *EstimateABTestResponse) GetDurationDaysOk() (*int64, bool) {
+ if o == nil || o.DurationDays == nil {
+ return nil, false
+ }
+ return o.DurationDays, true
+}
+
+// HasDurationDays returns a boolean if a field has been set.
+func (o *EstimateABTestResponse) HasDurationDays() bool {
+ if o != nil && o.DurationDays != nil {
+ return true
+ }
+
+ return false
+}
+
+// SetDurationDays gets a reference to the given int64 and assigns it to the DurationDays field.
+func (o *EstimateABTestResponse) SetDurationDays(v int64) *EstimateABTestResponse {
+ o.DurationDays = &v
+ return o
+}
+
+// GetControlSampleSize returns the ControlSampleSize field value if set, zero value otherwise.
+func (o *EstimateABTestResponse) GetControlSampleSize() int64 {
+ if o == nil || o.ControlSampleSize == nil {
+ var ret int64
+ return ret
+ }
+ return *o.ControlSampleSize
+}
+
+// GetControlSampleSizeOk returns a tuple with the ControlSampleSize field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *EstimateABTestResponse) GetControlSampleSizeOk() (*int64, bool) {
+ if o == nil || o.ControlSampleSize == nil {
+ return nil, false
+ }
+ return o.ControlSampleSize, true
+}
+
+// HasControlSampleSize returns a boolean if a field has been set.
+func (o *EstimateABTestResponse) HasControlSampleSize() bool {
+ if o != nil && o.ControlSampleSize != nil {
+ return true
+ }
+
+ return false
+}
+
+// SetControlSampleSize gets a reference to the given int64 and assigns it to the ControlSampleSize field.
+func (o *EstimateABTestResponse) SetControlSampleSize(v int64) *EstimateABTestResponse {
+ o.ControlSampleSize = &v
+ return o
+}
+
+// GetExperimentSampleSize returns the ExperimentSampleSize field value if set, zero value otherwise.
+func (o *EstimateABTestResponse) GetExperimentSampleSize() int64 {
+ if o == nil || o.ExperimentSampleSize == nil {
+ var ret int64
+ return ret
+ }
+ return *o.ExperimentSampleSize
+}
+
+// GetExperimentSampleSizeOk returns a tuple with the ExperimentSampleSize field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *EstimateABTestResponse) GetExperimentSampleSizeOk() (*int64, bool) {
+ if o == nil || o.ExperimentSampleSize == nil {
+ return nil, false
+ }
+ return o.ExperimentSampleSize, true
+}
+
+// HasExperimentSampleSize returns a boolean if a field has been set.
+func (o *EstimateABTestResponse) HasExperimentSampleSize() bool {
+ if o != nil && o.ExperimentSampleSize != nil {
+ return true
+ }
+
+ return false
+}
+
+// SetExperimentSampleSize gets a reference to the given int64 and assigns it to the ExperimentSampleSize field.
+func (o *EstimateABTestResponse) SetExperimentSampleSize(v int64) *EstimateABTestResponse {
+ o.ExperimentSampleSize = &v
+ return o
+}
+
+func (o EstimateABTestResponse) MarshalJSON() ([]byte, error) {
+ toSerialize := map[string]any{}
+ if o.DurationDays != nil {
+ toSerialize["durationDays"] = o.DurationDays
+ }
+ if o.ControlSampleSize != nil {
+ toSerialize["controlSampleSize"] = o.ControlSampleSize
+ }
+ if o.ExperimentSampleSize != nil {
+ toSerialize["experimentSampleSize"] = o.ExperimentSampleSize
+ }
+ serialized, err := json.Marshal(toSerialize)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal EstimateABTestResponse: %w", err)
+ }
+
+ return serialized, nil
+}
+
+func (o EstimateABTestResponse) String() string {
+ out := ""
+ out += fmt.Sprintf(" durationDays=%v\n", o.DurationDays)
+ out += fmt.Sprintf(" controlSampleSize=%v\n", o.ControlSampleSize)
+ out += fmt.Sprintf(" experimentSampleSize=%v\n", o.ExperimentSampleSize)
+ return fmt.Sprintf("EstimateABTestResponse {\n%s}", out)
+}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_configuration.go b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_configuration.go
new file mode 100644
index 00000000000..4bf95184c6d
--- /dev/null
+++ b/clients/algoliasearch-client-go/algolia/abtesting/model_estimate_configuration.go
@@ -0,0 +1,164 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+package abtesting
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// EstimateConfiguration A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+type EstimateConfiguration struct {
+ Outliers *Outliers `json:"outliers,omitempty"`
+ EmptySearch *EmptySearch `json:"emptySearch,omitempty"`
+ MinimumDetectableEffect MinimumDetectableEffect `json:"minimumDetectableEffect"`
+}
+
+type EstimateConfigurationOption func(f *EstimateConfiguration)
+
+func WithEstimateConfigurationOutliers(val Outliers) EstimateConfigurationOption {
+ return func(f *EstimateConfiguration) {
+ f.Outliers = &val
+ }
+}
+
+func WithEstimateConfigurationEmptySearch(val EmptySearch) EstimateConfigurationOption {
+ return func(f *EstimateConfiguration) {
+ f.EmptySearch = &val
+ }
+}
+
+// NewEstimateConfiguration instantiates a new EstimateConfiguration object
+// This constructor will assign default values to properties that have it defined,
+// and makes sure properties required by API are set, but the set of arguments
+// will change when the set of required properties is changed.
+func NewEstimateConfiguration(minimumDetectableEffect MinimumDetectableEffect, opts ...EstimateConfigurationOption) *EstimateConfiguration {
+ this := &EstimateConfiguration{}
+ this.MinimumDetectableEffect = minimumDetectableEffect
+ for _, opt := range opts {
+ opt(this)
+ }
+ return this
+}
+
+// NewEmptyEstimateConfiguration return a pointer to an empty EstimateConfiguration object.
+func NewEmptyEstimateConfiguration() *EstimateConfiguration {
+ return &EstimateConfiguration{}
+}
+
+// GetOutliers returns the Outliers field value if set, zero value otherwise.
+func (o *EstimateConfiguration) GetOutliers() Outliers {
+ if o == nil || o.Outliers == nil {
+ var ret Outliers
+ return ret
+ }
+ return *o.Outliers
+}
+
+// GetOutliersOk returns a tuple with the Outliers field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *EstimateConfiguration) GetOutliersOk() (*Outliers, bool) {
+ if o == nil || o.Outliers == nil {
+ return nil, false
+ }
+ return o.Outliers, true
+}
+
+// HasOutliers returns a boolean if a field has been set.
+func (o *EstimateConfiguration) HasOutliers() bool {
+ if o != nil && o.Outliers != nil {
+ return true
+ }
+
+ return false
+}
+
+// SetOutliers gets a reference to the given Outliers and assigns it to the Outliers field.
+func (o *EstimateConfiguration) SetOutliers(v *Outliers) *EstimateConfiguration {
+ o.Outliers = v
+ return o
+}
+
+// GetEmptySearch returns the EmptySearch field value if set, zero value otherwise.
+func (o *EstimateConfiguration) GetEmptySearch() EmptySearch {
+ if o == nil || o.EmptySearch == nil {
+ var ret EmptySearch
+ return ret
+ }
+ return *o.EmptySearch
+}
+
+// GetEmptySearchOk returns a tuple with the EmptySearch field value if set, nil otherwise
+// and a boolean to check if the value has been set.
+func (o *EstimateConfiguration) GetEmptySearchOk() (*EmptySearch, bool) {
+ if o == nil || o.EmptySearch == nil {
+ return nil, false
+ }
+ return o.EmptySearch, true
+}
+
+// HasEmptySearch returns a boolean if a field has been set.
+func (o *EstimateConfiguration) HasEmptySearch() bool {
+ if o != nil && o.EmptySearch != nil {
+ return true
+ }
+
+ return false
+}
+
+// SetEmptySearch gets a reference to the given EmptySearch and assigns it to the EmptySearch field.
+func (o *EstimateConfiguration) SetEmptySearch(v *EmptySearch) *EstimateConfiguration {
+ o.EmptySearch = v
+ return o
+}
+
+// GetMinimumDetectableEffect returns the MinimumDetectableEffect field value.
+func (o *EstimateConfiguration) GetMinimumDetectableEffect() MinimumDetectableEffect {
+ if o == nil {
+ var ret MinimumDetectableEffect
+ return ret
+ }
+
+ return o.MinimumDetectableEffect
+}
+
+// GetMinimumDetectableEffectOk returns a tuple with the MinimumDetectableEffect field value
+// and a boolean to check if the value has been set.
+func (o *EstimateConfiguration) GetMinimumDetectableEffectOk() (*MinimumDetectableEffect, bool) {
+ if o == nil {
+ return nil, false
+ }
+ return &o.MinimumDetectableEffect, true
+}
+
+// SetMinimumDetectableEffect sets field value.
+func (o *EstimateConfiguration) SetMinimumDetectableEffect(v *MinimumDetectableEffect) *EstimateConfiguration {
+ o.MinimumDetectableEffect = *v
+ return o
+}
+
+func (o EstimateConfiguration) MarshalJSON() ([]byte, error) {
+ toSerialize := map[string]any{}
+ if o.Outliers != nil {
+ toSerialize["outliers"] = o.Outliers
+ }
+ if o.EmptySearch != nil {
+ toSerialize["emptySearch"] = o.EmptySearch
+ }
+ if true {
+ toSerialize["minimumDetectableEffect"] = o.MinimumDetectableEffect
+ }
+ serialized, err := json.Marshal(toSerialize)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal EstimateConfiguration: %w", err)
+ }
+
+ return serialized, nil
+}
+
+func (o EstimateConfiguration) String() string {
+ out := ""
+ out += fmt.Sprintf(" outliers=%v\n", o.Outliers)
+ out += fmt.Sprintf(" emptySearch=%v\n", o.EmptySearch)
+ out += fmt.Sprintf(" minimumDetectableEffect=%v\n", o.MinimumDetectableEffect)
+ return fmt.Sprintf("EstimateConfiguration {\n%s}", out)
+}
diff --git a/clients/algoliasearch-client-go/algolia/abtesting/model_minimum_detectable_effect.go b/clients/algoliasearch-client-go/algolia/abtesting/model_minimum_detectable_effect.go
index 7bab5dc57ef..a73900199e4 100644
--- a/clients/algoliasearch-client-go/algolia/abtesting/model_minimum_detectable_effect.go
+++ b/clients/algoliasearch-client-go/algolia/abtesting/model_minimum_detectable_effect.go
@@ -9,33 +9,18 @@ import (
// MinimumDetectableEffect Configuration for the smallest difference between test variants you want to detect.
type MinimumDetectableEffect struct {
// Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
- Size *float64 `json:"size,omitempty"`
- Effect *Effect `json:"effect,omitempty"`
-}
-
-type MinimumDetectableEffectOption func(f *MinimumDetectableEffect)
-
-func WithMinimumDetectableEffectSize(val float64) MinimumDetectableEffectOption {
- return func(f *MinimumDetectableEffect) {
- f.Size = &val
- }
-}
-
-func WithMinimumDetectableEffectEffect(val Effect) MinimumDetectableEffectOption {
- return func(f *MinimumDetectableEffect) {
- f.Effect = &val
- }
+ Size float64 `json:"size"`
+ Metric EffectMetric `json:"metric"`
}
// NewMinimumDetectableEffect instantiates a new MinimumDetectableEffect object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed.
-func NewMinimumDetectableEffect(opts ...MinimumDetectableEffectOption) *MinimumDetectableEffect {
+func NewMinimumDetectableEffect(size float64, metric EffectMetric) *MinimumDetectableEffect {
this := &MinimumDetectableEffect{}
- for _, opt := range opts {
- opt(this)
- }
+ this.Size = size
+ this.Metric = metric
return this
}
@@ -44,79 +29,63 @@ func NewEmptyMinimumDetectableEffect() *MinimumDetectableEffect {
return &MinimumDetectableEffect{}
}
-// GetSize returns the Size field value if set, zero value otherwise.
+// GetSize returns the Size field value.
func (o *MinimumDetectableEffect) GetSize() float64 {
- if o == nil || o.Size == nil {
+ if o == nil {
var ret float64
return ret
}
- return *o.Size
+
+ return o.Size
}
-// GetSizeOk returns a tuple with the Size field value if set, nil otherwise
+// GetSizeOk returns a tuple with the Size field value
// and a boolean to check if the value has been set.
func (o *MinimumDetectableEffect) GetSizeOk() (*float64, bool) {
- if o == nil || o.Size == nil {
+ if o == nil {
return nil, false
}
- return o.Size, true
+ return &o.Size, true
}
-// HasSize returns a boolean if a field has been set.
-func (o *MinimumDetectableEffect) HasSize() bool {
- if o != nil && o.Size != nil {
- return true
- }
-
- return false
-}
-
-// SetSize gets a reference to the given float64 and assigns it to the Size field.
+// SetSize sets field value.
func (o *MinimumDetectableEffect) SetSize(v float64) *MinimumDetectableEffect {
- o.Size = &v
+ o.Size = v
return o
}
-// GetEffect returns the Effect field value if set, zero value otherwise.
-func (o *MinimumDetectableEffect) GetEffect() Effect {
- if o == nil || o.Effect == nil {
- var ret Effect
+// GetMetric returns the Metric field value.
+func (o *MinimumDetectableEffect) GetMetric() EffectMetric {
+ if o == nil {
+ var ret EffectMetric
return ret
}
- return *o.Effect
+
+ return o.Metric
}
-// GetEffectOk returns a tuple with the Effect field value if set, nil otherwise
+// GetMetricOk returns a tuple with the Metric field value
// and a boolean to check if the value has been set.
-func (o *MinimumDetectableEffect) GetEffectOk() (*Effect, bool) {
- if o == nil || o.Effect == nil {
+func (o *MinimumDetectableEffect) GetMetricOk() (*EffectMetric, bool) {
+ if o == nil {
return nil, false
}
- return o.Effect, true
-}
-
-// HasEffect returns a boolean if a field has been set.
-func (o *MinimumDetectableEffect) HasEffect() bool {
- if o != nil && o.Effect != nil {
- return true
- }
-
- return false
+ return &o.Metric, true
}
-// SetEffect gets a reference to the given Effect and assigns it to the Effect field.
-func (o *MinimumDetectableEffect) SetEffect(v Effect) *MinimumDetectableEffect {
- o.Effect = &v
+// SetMetric sets field value.
+func (o *MinimumDetectableEffect) SetMetric(v EffectMetric) *MinimumDetectableEffect {
+ o.Metric = v
return o
}
func (o MinimumDetectableEffect) MarshalJSON() ([]byte, error) {
toSerialize := map[string]any{}
- if o.Size != nil {
+ if true {
toSerialize["size"] = o.Size
}
- if o.Effect != nil {
- toSerialize["effect"] = o.Effect
+ if true {
+ toSerialize["metric"] = o.Metric
}
serialized, err := json.Marshal(toSerialize)
if err != nil {
@@ -129,6 +98,6 @@ func (o MinimumDetectableEffect) MarshalJSON() ([]byte, error) {
func (o MinimumDetectableEffect) String() string {
out := ""
out += fmt.Sprintf(" size=%v\n", o.Size)
- out += fmt.Sprintf(" effect=%v\n", o.Effect)
+ out += fmt.Sprintf(" metric=%v\n", o.Metric)
return fmt.Sprintf("MinimumDetectableEffect {\n%s}", out)
}
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/api/AbtestingClient.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/api/AbtestingClient.java
index e12cf180ab2..5592d2e3227 100644
--- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/api/AbtestingClient.java
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/api/AbtestingClient.java
@@ -574,6 +574,62 @@ public CompletableFuture deleteABTestAsync(@Nonnull Integer id)
return this.deleteABTestAsync(id, null);
}
+ /**
+ * Given the traffic percentage and the expected effect size, this endpoint estimates the sample
+ * size and duration of an A/B test based on historical traffic.
+ *
+ * @param estimateABTestRequest (required)
+ * @param requestOptions The requestOptions to send along with the query, they will be merged with
+ * the transporter requestOptions.
+ * @throws AlgoliaRuntimeException If it fails to process the API call
+ */
+ public EstimateABTestResponse estimateABTest(@Nonnull EstimateABTestRequest estimateABTestRequest, RequestOptions requestOptions)
+ throws AlgoliaRuntimeException {
+ return LaunderThrowable.await(estimateABTestAsync(estimateABTestRequest, requestOptions));
+ }
+
+ /**
+ * Given the traffic percentage and the expected effect size, this endpoint estimates the sample
+ * size and duration of an A/B test based on historical traffic.
+ *
+ * @param estimateABTestRequest (required)
+ * @throws AlgoliaRuntimeException If it fails to process the API call
+ */
+ public EstimateABTestResponse estimateABTest(@Nonnull EstimateABTestRequest estimateABTestRequest) throws AlgoliaRuntimeException {
+ return this.estimateABTest(estimateABTestRequest, null);
+ }
+
+ /**
+ * (asynchronously) Given the traffic percentage and the expected effect size, this endpoint
+ * estimates the sample size and duration of an A/B test based on historical traffic.
+ *
+ * @param estimateABTestRequest (required)
+ * @param requestOptions The requestOptions to send along with the query, they will be merged with
+ * the transporter requestOptions.
+ * @throws AlgoliaRuntimeException If it fails to process the API call
+ */
+ public CompletableFuture estimateABTestAsync(
+ @Nonnull EstimateABTestRequest estimateABTestRequest,
+ RequestOptions requestOptions
+ ) throws AlgoliaRuntimeException {
+ Parameters.requireNonNull(estimateABTestRequest, "Parameter `estimateABTestRequest` is required when calling `estimateABTest`.");
+
+ HttpRequest request = HttpRequest.builder().setPath("/2/abtests/estimate").setMethod("POST").setBody(estimateABTestRequest).build();
+ return executeAsync(request, requestOptions, new TypeReference() {});
+ }
+
+ /**
+ * (asynchronously) Given the traffic percentage and the expected effect size, this endpoint
+ * estimates the sample size and duration of an A/B test based on historical traffic.
+ *
+ * @param estimateABTestRequest (required)
+ * @throws AlgoliaRuntimeException If it fails to process the API call
+ */
+ public CompletableFuture estimateABTestAsync(@Nonnull EstimateABTestRequest estimateABTestRequest)
+ throws AlgoliaRuntimeException {
+ return this.estimateABTestAsync(estimateABTestRequest, null);
+ }
+
/**
* Retrieves the details for an A/B test by its ID.
*
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/Effect.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EffectMetric.java
similarity index 84%
rename from clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/Effect.java
rename to clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EffectMetric.java
index c21382c569c..cf81969f90b 100644
--- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/Effect.java
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EffectMetric.java
@@ -7,7 +7,7 @@
import com.fasterxml.jackson.databind.annotation.*;
/** Metric for which you want to detect the smallest relative difference. */
-public enum Effect {
+public enum EffectMetric {
ADD_TO_CART_RATE("addToCartRate"),
CLICK_THROUGH_RATE("clickThroughRate"),
@@ -18,7 +18,7 @@ public enum Effect {
private final String value;
- Effect(String value) {
+ EffectMetric(String value) {
this.value = value;
}
@@ -33,8 +33,8 @@ public String toString() {
}
@JsonCreator
- public static Effect fromValue(String value) {
- for (Effect b : Effect.values()) {
+ public static EffectMetric fromValue(String value) {
+ for (EffectMetric b : EffectMetric.values()) {
if (b.value.equals(value)) {
return b;
}
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestRequest.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestRequest.java
new file mode 100644
index 00000000000..a84e697804a
--- /dev/null
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestRequest.java
@@ -0,0 +1,87 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost
+// - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+package com.algolia.model.abtesting;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/** EstimateABTestRequest */
+public class EstimateABTestRequest {
+
+ @JsonProperty("configuration")
+ private EstimateConfiguration configuration;
+
+ @JsonProperty("variants")
+ private List variants = new ArrayList<>();
+
+ public EstimateABTestRequest setConfiguration(EstimateConfiguration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ /** Get configuration */
+ @javax.annotation.Nonnull
+ public EstimateConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ public EstimateABTestRequest setVariants(List variants) {
+ this.variants = variants;
+ return this;
+ }
+
+ public EstimateABTestRequest addVariants(AddABTestsVariant variantsItem) {
+ this.variants.add(variantsItem);
+ return this;
+ }
+
+ /** A/B test variants. */
+ @javax.annotation.Nonnull
+ public List getVariants() {
+ return variants;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EstimateABTestRequest estimateABTestRequest = (EstimateABTestRequest) o;
+ return (
+ Objects.equals(this.configuration, estimateABTestRequest.configuration) &&
+ Objects.equals(this.variants, estimateABTestRequest.variants)
+ );
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(configuration, variants);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EstimateABTestRequest {\n");
+ sb.append(" configuration: ").append(toIndentedString(configuration)).append("\n");
+ sb.append(" variants: ").append(toIndentedString(variants)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestResponse.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestResponse.java
new file mode 100644
index 00000000000..3b6f670bd99
--- /dev/null
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateABTestResponse.java
@@ -0,0 +1,105 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost
+// - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+package com.algolia.model.abtesting;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.annotation.*;
+import java.util.Objects;
+
+/** EstimateABTestResponse */
+public class EstimateABTestResponse {
+
+ @JsonProperty("durationDays")
+ private Long durationDays;
+
+ @JsonProperty("controlSampleSize")
+ private Long controlSampleSize;
+
+ @JsonProperty("experimentSampleSize")
+ private Long experimentSampleSize;
+
+ public EstimateABTestResponse setDurationDays(Long durationDays) {
+ this.durationDays = durationDays;
+ return this;
+ }
+
+ /**
+ * Estimated number of days needed to reach the sample sizes required for detecting the configured
+ * effect. This value is based on historical traffic.
+ */
+ @javax.annotation.Nullable
+ public Long getDurationDays() {
+ return durationDays;
+ }
+
+ public EstimateABTestResponse setControlSampleSize(Long controlSampleSize) {
+ this.controlSampleSize = controlSampleSize;
+ return this;
+ }
+
+ /**
+ * Number of tracked searches needed to be able to detect the configured effect for the control
+ * variant.
+ */
+ @javax.annotation.Nullable
+ public Long getControlSampleSize() {
+ return controlSampleSize;
+ }
+
+ public EstimateABTestResponse setExperimentSampleSize(Long experimentSampleSize) {
+ this.experimentSampleSize = experimentSampleSize;
+ return this;
+ }
+
+ /**
+ * Number of tracked searches needed to be able to detect the configured effect for the experiment
+ * variant.
+ */
+ @javax.annotation.Nullable
+ public Long getExperimentSampleSize() {
+ return experimentSampleSize;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EstimateABTestResponse estimateABTestResponse = (EstimateABTestResponse) o;
+ return (
+ Objects.equals(this.durationDays, estimateABTestResponse.durationDays) &&
+ Objects.equals(this.controlSampleSize, estimateABTestResponse.controlSampleSize) &&
+ Objects.equals(this.experimentSampleSize, estimateABTestResponse.experimentSampleSize)
+ );
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(durationDays, controlSampleSize, experimentSampleSize);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EstimateABTestResponse {\n");
+ sb.append(" durationDays: ").append(toIndentedString(durationDays)).append("\n");
+ sb.append(" controlSampleSize: ").append(toIndentedString(controlSampleSize)).append("\n");
+ sb.append(" experimentSampleSize: ").append(toIndentedString(experimentSampleSize)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateConfiguration.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateConfiguration.java
new file mode 100644
index 00000000000..0e95fddb900
--- /dev/null
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/EstimateConfiguration.java
@@ -0,0 +1,99 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost
+// - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+package com.algolia.model.abtesting;
+
+import com.fasterxml.jackson.annotation.*;
+import com.fasterxml.jackson.databind.annotation.*;
+import java.util.Objects;
+
+/**
+ * A/B test configuration for estimating the sample size and duration using minimum detectable
+ * effect.
+ */
+public class EstimateConfiguration {
+
+ @JsonProperty("outliers")
+ private Outliers outliers;
+
+ @JsonProperty("emptySearch")
+ private EmptySearch emptySearch;
+
+ @JsonProperty("minimumDetectableEffect")
+ private MinimumDetectableEffect minimumDetectableEffect;
+
+ public EstimateConfiguration setOutliers(Outliers outliers) {
+ this.outliers = outliers;
+ return this;
+ }
+
+ /** Get outliers */
+ @javax.annotation.Nullable
+ public Outliers getOutliers() {
+ return outliers;
+ }
+
+ public EstimateConfiguration setEmptySearch(EmptySearch emptySearch) {
+ this.emptySearch = emptySearch;
+ return this;
+ }
+
+ /** Get emptySearch */
+ @javax.annotation.Nullable
+ public EmptySearch getEmptySearch() {
+ return emptySearch;
+ }
+
+ public EstimateConfiguration setMinimumDetectableEffect(MinimumDetectableEffect minimumDetectableEffect) {
+ this.minimumDetectableEffect = minimumDetectableEffect;
+ return this;
+ }
+
+ /** Get minimumDetectableEffect */
+ @javax.annotation.Nonnull
+ public MinimumDetectableEffect getMinimumDetectableEffect() {
+ return minimumDetectableEffect;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ EstimateConfiguration estimateConfiguration = (EstimateConfiguration) o;
+ return (
+ Objects.equals(this.outliers, estimateConfiguration.outliers) &&
+ Objects.equals(this.emptySearch, estimateConfiguration.emptySearch) &&
+ Objects.equals(this.minimumDetectableEffect, estimateConfiguration.minimumDetectableEffect)
+ );
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(outliers, emptySearch, minimumDetectableEffect);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("class EstimateConfiguration {\n");
+ sb.append(" outliers: ").append(toIndentedString(outliers)).append("\n");
+ sb.append(" emptySearch: ").append(toIndentedString(emptySearch)).append("\n");
+ sb.append(" minimumDetectableEffect: ").append(toIndentedString(minimumDetectableEffect)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/MinimumDetectableEffect.java b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/MinimumDetectableEffect.java
index 202ac09fe10..bd4cd428b90 100644
--- a/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/MinimumDetectableEffect.java
+++ b/clients/algoliasearch-client-java/algoliasearch/src/main/java/com/algolia/model/abtesting/MinimumDetectableEffect.java
@@ -13,8 +13,8 @@ public class MinimumDetectableEffect {
@JsonProperty("size")
private Double size;
- @JsonProperty("effect")
- private Effect effect;
+ @JsonProperty("metric")
+ private EffectMetric metric;
public MinimumDetectableEffect setSize(Double size) {
this.size = size;
@@ -25,20 +25,20 @@ public MinimumDetectableEffect setSize(Double size) {
* Smallest difference in an observable metric between variants. For example, to detect a 10%
* difference between variants, set this value to 0.1. minimum: 0 maximum: 1
*/
- @javax.annotation.Nullable
+ @javax.annotation.Nonnull
public Double getSize() {
return size;
}
- public MinimumDetectableEffect setEffect(Effect effect) {
- this.effect = effect;
+ public MinimumDetectableEffect setMetric(EffectMetric metric) {
+ this.metric = metric;
return this;
}
- /** Get effect */
- @javax.annotation.Nullable
- public Effect getEffect() {
- return effect;
+ /** Get metric */
+ @javax.annotation.Nonnull
+ public EffectMetric getMetric() {
+ return metric;
}
@Override
@@ -50,12 +50,12 @@ public boolean equals(Object o) {
return false;
}
MinimumDetectableEffect minimumDetectableEffect = (MinimumDetectableEffect) o;
- return Objects.equals(this.size, minimumDetectableEffect.size) && Objects.equals(this.effect, minimumDetectableEffect.effect);
+ return Objects.equals(this.size, minimumDetectableEffect.size) && Objects.equals(this.metric, minimumDetectableEffect.metric);
}
@Override
public int hashCode() {
- return Objects.hash(size, effect);
+ return Objects.hash(size, metric);
}
@Override
@@ -63,7 +63,7 @@ public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class MinimumDetectableEffect {\n");
sb.append(" size: ").append(toIndentedString(size)).append("\n");
- sb.append(" effect: ").append(toIndentedString(effect)).append("\n");
+ sb.append(" metric: ").append(toIndentedString(metric)).append("\n");
sb.append("}");
return sb.toString();
}
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/effect.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/effectMetric.ts
similarity index 72%
rename from clients/algoliasearch-client-javascript/packages/client-abtesting/model/effect.ts
rename to clients/algoliasearch-client-javascript/packages/client-abtesting/model/effectMetric.ts
index b884ebfb125..dc7e6ee7796 100644
--- a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/effect.ts
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/effectMetric.ts
@@ -3,4 +3,4 @@
/**
* Metric for which you want to detect the smallest relative difference.
*/
-export type Effect = 'addToCartRate' | 'clickThroughRate' | 'conversionRate' | 'purchaseRate';
+export type EffectMetric = 'addToCartRate' | 'clickThroughRate' | 'conversionRate' | 'purchaseRate';
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestRequest.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestRequest.ts
new file mode 100644
index 00000000000..1c5e6c3dbaa
--- /dev/null
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestRequest.ts
@@ -0,0 +1,13 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import type { AddABTestsVariant } from './addABTestsVariant';
+import type { EstimateConfiguration } from './estimateConfiguration';
+
+export type EstimateABTestRequest = {
+ configuration: EstimateConfiguration;
+
+ /**
+ * A/B test variants.
+ */
+ variants: Array;
+};
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestResponse.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestResponse.ts
new file mode 100644
index 00000000000..edc4f7c304e
--- /dev/null
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateABTestResponse.ts
@@ -0,0 +1,18 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+export type EstimateABTestResponse = {
+ /**
+ * Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ */
+ durationDays?: number;
+
+ /**
+ * Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ */
+ controlSampleSize?: number;
+
+ /**
+ * Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ */
+ experimentSampleSize?: number;
+};
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateConfiguration.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateConfiguration.ts
new file mode 100644
index 00000000000..ee60c3c509f
--- /dev/null
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/estimateConfiguration.ts
@@ -0,0 +1,16 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import type { EmptySearch } from './emptySearch';
+import type { MinimumDetectableEffect } from './minimumDetectableEffect';
+import type { Outliers } from './outliers';
+
+/**
+ * A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+ */
+export type EstimateConfiguration = {
+ outliers?: Outliers;
+
+ emptySearch?: EmptySearch;
+
+ minimumDetectableEffect: MinimumDetectableEffect;
+};
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/index.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/index.ts
index 8af7fe70c87..980f1f4bcad 100644
--- a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/index.ts
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/index.ts
@@ -10,10 +10,13 @@ export * from './addABTestsVariant';
export * from './clientMethodProps';
export * from './currency';
export * from './customSearchParams';
-export * from './effect';
+export * from './effectMetric';
export * from './emptySearch';
export * from './emptySearchFilter';
export * from './errorBase';
+export * from './estimateABTestRequest';
+export * from './estimateABTestResponse';
+export * from './estimateConfiguration';
export * from './filterEffects';
export * from './listABTestsResponse';
export * from './minimumDetectableEffect';
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/minimumDetectableEffect.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/minimumDetectableEffect.ts
index 4b9bc0dfa1c..ecd87dcc1f5 100644
--- a/clients/algoliasearch-client-javascript/packages/client-abtesting/model/minimumDetectableEffect.ts
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/model/minimumDetectableEffect.ts
@@ -1,6 +1,6 @@
// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
-import type { Effect } from './effect';
+import type { EffectMetric } from './effectMetric';
/**
* Configuration for the smallest difference between test variants you want to detect.
@@ -9,7 +9,7 @@ export type MinimumDetectableEffect = {
/**
* Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
*/
- size?: number;
+ size: number;
- effect?: Effect;
+ metric: EffectMetric;
};
diff --git a/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingClient.ts b/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingClient.ts
index f85053920f1..cb08a55171a 100644
--- a/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingClient.ts
+++ b/clients/algoliasearch-client-javascript/packages/client-abtesting/src/abtestingClient.ts
@@ -14,6 +14,8 @@ import type { ABTest } from '../model/aBTest';
import type { ABTestResponse } from '../model/aBTestResponse';
import type { AddABTestsRequest } from '../model/addABTestsRequest';
+import type { EstimateABTestRequest } from '../model/estimateABTestRequest';
+import type { EstimateABTestResponse } from '../model/estimateABTestResponse';
import type { ListABTestsResponse } from '../model/listABTestsResponse';
import type { ScheduleABTestResponse } from '../model/scheduleABTestResponse';
import type { ScheduleABTestsRequest } from '../model/scheduleABTestsRequest';
@@ -298,6 +300,44 @@ export function createAbtestingClient({
return transporter.request(request, requestOptions);
},
+ /**
+ * Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ *
+ * Required API Key ACLs:
+ * - analytics
+ * @param estimateABTestRequest - The estimateABTestRequest object.
+ * @param requestOptions - The requestOptions to send along with the query, they will be merged with the transporter requestOptions.
+ */
+ estimateABTest(
+ estimateABTestRequest: EstimateABTestRequest,
+ requestOptions?: RequestOptions,
+ ): Promise {
+ if (!estimateABTestRequest) {
+ throw new Error('Parameter `estimateABTestRequest` is required when calling `estimateABTest`.');
+ }
+
+ if (!estimateABTestRequest.configuration) {
+ throw new Error('Parameter `estimateABTestRequest.configuration` is required when calling `estimateABTest`.');
+ }
+ if (!estimateABTestRequest.variants) {
+ throw new Error('Parameter `estimateABTestRequest.variants` is required when calling `estimateABTest`.');
+ }
+
+ const requestPath = '/2/abtests/estimate';
+ const headers: Headers = {};
+ const queryParameters: QueryParameters = {};
+
+ const request: Request = {
+ method: 'POST',
+ path: requestPath,
+ queryParameters,
+ headers,
+ data: estimateABTestRequest,
+ };
+
+ return transporter.request(request, requestOptions);
+ },
+
/**
* Retrieves the details for an A/B test by its ID.
*
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/api/AbtestingClient.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/api/AbtestingClient.kt
index 4598df9a1c7..812057dc102 100644
--- a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/api/AbtestingClient.kt
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/api/AbtestingClient.kt
@@ -155,6 +155,26 @@ public class AbtestingClient(
)
}
+ /**
+ * Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ *
+ * Required API Key ACLs:
+ * - analytics
+ * @param estimateABTestRequest
+ * @param requestOptions additional request configuration.
+ */
+ public suspend fun estimateABTest(estimateABTestRequest: EstimateABTestRequest, requestOptions: RequestOptions? = null): EstimateABTestResponse {
+ val requestConfig = RequestConfig(
+ method = RequestMethod.POST,
+ path = listOf("2", "abtests", "estimate"),
+ body = estimateABTestRequest,
+ )
+ return requester.execute(
+ requestConfig = requestConfig,
+ requestOptions = requestOptions,
+ )
+ }
+
/**
* Retrieves the details for an A/B test by its ID.
*
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/Effect.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EffectMetric.kt
similarity index 91%
rename from clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/Effect.kt
rename to clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EffectMetric.kt
index a73b9468590..bd3326e27d9 100644
--- a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/Effect.kt
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EffectMetric.kt
@@ -7,7 +7,7 @@ import kotlinx.serialization.*
* Metric for which you want to detect the smallest relative difference.
*/
@Serializable
-public enum class Effect(public val value: kotlin.String) {
+public enum class EffectMetric(public val value: kotlin.String) {
@SerialName(value = "addToCartRate")
AddToCartRate("addToCartRate"),
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestRequest.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestRequest.kt
new file mode 100644
index 00000000000..9e1a7d32837
--- /dev/null
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestRequest.kt
@@ -0,0 +1,20 @@
+/** Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT. */
+package com.algolia.client.model.abtesting
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+
+/**
+ * EstimateABTestRequest
+ *
+ * @param configuration
+ * @param variants A/B test variants.
+ */
+@Serializable
+public data class EstimateABTestRequest(
+
+ @SerialName(value = "configuration") val configuration: EstimateConfiguration,
+
+ /** A/B test variants. */
+ @SerialName(value = "variants") val variants: List,
+)
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestResponse.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestResponse.kt
new file mode 100644
index 00000000000..73c4e0c9037
--- /dev/null
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateABTestResponse.kt
@@ -0,0 +1,25 @@
+/** Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT. */
+package com.algolia.client.model.abtesting
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+
+/**
+ * EstimateABTestResponse
+ *
+ * @param durationDays Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ * @param controlSampleSize Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ * @param experimentSampleSize Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ */
+@Serializable
+public data class EstimateABTestResponse(
+
+ /** Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic. */
+ @SerialName(value = "durationDays") val durationDays: Long? = null,
+
+ /** Number of tracked searches needed to be able to detect the configured effect for the control variant. */
+ @SerialName(value = "controlSampleSize") val controlSampleSize: Long? = null,
+
+ /** Number of tracked searches needed to be able to detect the configured effect for the experiment variant. */
+ @SerialName(value = "experimentSampleSize") val experimentSampleSize: Long? = null,
+)
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateConfiguration.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateConfiguration.kt
new file mode 100644
index 00000000000..b6492afdcb0
--- /dev/null
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/EstimateConfiguration.kt
@@ -0,0 +1,22 @@
+/** Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT. */
+package com.algolia.client.model.abtesting
+
+import kotlinx.serialization.*
+import kotlinx.serialization.json.*
+
+/**
+ * A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+ *
+ * @param minimumDetectableEffect
+ * @param outliers
+ * @param emptySearch
+ */
+@Serializable
+public data class EstimateConfiguration(
+
+ @SerialName(value = "minimumDetectableEffect") val minimumDetectableEffect: MinimumDetectableEffect,
+
+ @SerialName(value = "outliers") val outliers: Outliers? = null,
+
+ @SerialName(value = "emptySearch") val emptySearch: EmptySearch? = null,
+)
diff --git a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/MinimumDetectableEffect.kt b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/MinimumDetectableEffect.kt
index d854da53409..4e5e3543dfa 100644
--- a/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/MinimumDetectableEffect.kt
+++ b/clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/model/abtesting/MinimumDetectableEffect.kt
@@ -8,13 +8,13 @@ import kotlinx.serialization.json.*
* Configuration for the smallest difference between test variants you want to detect.
*
* @param size Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
- * @param effect
+ * @param metric
*/
@Serializable
public data class MinimumDetectableEffect(
/** Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1. */
- @SerialName(value = "size") val size: Double? = null,
+ @SerialName(value = "size") val size: Double,
- @SerialName(value = "effect") val effect: Effect? = null,
+ @SerialName(value = "metric") val metric: EffectMetric,
)
diff --git a/clients/algoliasearch-client-php/lib/Api/AbtestingClient.php b/clients/algoliasearch-client-php/lib/Api/AbtestingClient.php
index 88a45839c5d..13e5d1128f1 100644
--- a/clients/algoliasearch-client-php/lib/Api/AbtestingClient.php
+++ b/clients/algoliasearch-client-php/lib/Api/AbtestingClient.php
@@ -7,6 +7,7 @@
use Algolia\AlgoliaSearch\Algolia;
use Algolia\AlgoliaSearch\Configuration\AbtestingConfig;
use Algolia\AlgoliaSearch\Model\Abtesting\AddABTestsRequest;
+use Algolia\AlgoliaSearch\Model\Abtesting\EstimateABTestRequest;
use Algolia\AlgoliaSearch\Model\Abtesting\ScheduleABTestsRequest;
use Algolia\AlgoliaSearch\ObjectSerializer;
use Algolia\AlgoliaSearch\RetryStrategy\ApiWrapper;
@@ -338,6 +339,39 @@ public function deleteABTest($id, $requestOptions = [])
return $this->sendRequest('DELETE', $resourcePath, $headers, $queryParameters, $httpBody, $requestOptions);
}
+ /**
+ * Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ *
+ * Required API Key ACLs:
+ * - analytics
+ *
+ * @param array $estimateABTestRequest estimateABTestRequest (required)
+ * - $estimateABTestRequest['configuration'] => (array) (required)
+ * - $estimateABTestRequest['variants'] => (array) A/B test variants. (required)
+ *
+ * @see EstimateABTestRequest
+ *
+ * @param array $requestOptions the requestOptions to send along with the query, they will be merged with the transporter requestOptions
+ *
+ * @return \Algolia\AlgoliaSearch\Model\Abtesting\EstimateABTestResponse|array
+ */
+ public function estimateABTest($estimateABTestRequest, $requestOptions = [])
+ {
+ // verify the required parameter 'estimateABTestRequest' is set
+ if (!isset($estimateABTestRequest)) {
+ throw new \InvalidArgumentException(
+ 'Parameter `estimateABTestRequest` is required when calling `estimateABTest`.'
+ );
+ }
+
+ $resourcePath = '/2/abtests/estimate';
+ $queryParameters = [];
+ $headers = [];
+ $httpBody = $estimateABTestRequest;
+
+ return $this->sendRequest('POST', $resourcePath, $headers, $queryParameters, $httpBody, $requestOptions);
+ }
+
/**
* Retrieves the details for an A/B test by its ID.
*
diff --git a/clients/algoliasearch-client-php/lib/Model/Abtesting/Effect.php b/clients/algoliasearch-client-php/lib/Model/Abtesting/EffectMetric.php
similarity index 94%
rename from clients/algoliasearch-client-php/lib/Model/Abtesting/Effect.php
rename to clients/algoliasearch-client-php/lib/Model/Abtesting/EffectMetric.php
index ff96e387177..d171aaa8e3d 100644
--- a/clients/algoliasearch-client-php/lib/Model/Abtesting/Effect.php
+++ b/clients/algoliasearch-client-php/lib/Model/Abtesting/EffectMetric.php
@@ -5,13 +5,13 @@
namespace Algolia\AlgoliaSearch\Model\Abtesting;
/**
- * Effect Class Doc Comment.
+ * EffectMetric Class Doc Comment.
*
* @category Class
*
* @description Metric for which you want to detect the smallest relative difference.
*/
-class Effect
+class EffectMetric
{
/**
* Possible values of this enum.
diff --git a/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestRequest.php b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestRequest.php
new file mode 100644
index 00000000000..f2746c17681
--- /dev/null
+++ b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestRequest.php
@@ -0,0 +1,265 @@
+ '\Algolia\AlgoliaSearch\Model\Abtesting\EstimateConfiguration',
+ 'variants' => '\Algolia\AlgoliaSearch\Model\Abtesting\AddABTestsVariant[]',
+ ];
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @var string[]
+ */
+ protected static $modelFormats = [
+ 'configuration' => null,
+ 'variants' => null,
+ ];
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @var string[]
+ */
+ protected static $attributeMap = [
+ 'configuration' => 'configuration',
+ 'variants' => 'variants',
+ ];
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @var string[]
+ */
+ protected static $setters = [
+ 'configuration' => 'setConfiguration',
+ 'variants' => 'setVariants',
+ ];
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @var string[]
+ */
+ protected static $getters = [
+ 'configuration' => 'getConfiguration',
+ 'variants' => 'getVariants',
+ ];
+
+ /**
+ * Associative array for storing property values.
+ *
+ * @var mixed[]
+ */
+ protected $container = [];
+
+ /**
+ * Constructor.
+ *
+ * @param mixed[] $data Associated array of property values
+ */
+ public function __construct(?array $data = null)
+ {
+ if (isset($data['configuration'])) {
+ $this->container['configuration'] = $data['configuration'];
+ }
+ if (isset($data['variants'])) {
+ $this->container['variants'] = $data['variants'];
+ }
+ }
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @return array
+ */
+ public static function attributeMap()
+ {
+ return self::$attributeMap;
+ }
+
+ /**
+ * Array of property to type mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelTypes()
+ {
+ return self::$modelTypes;
+ }
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelFormats()
+ {
+ return self::$modelFormats;
+ }
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @return array
+ */
+ public static function setters()
+ {
+ return self::$setters;
+ }
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @return array
+ */
+ public static function getters()
+ {
+ return self::$getters;
+ }
+
+ /**
+ * Show all the invalid properties with reasons.
+ *
+ * @return array invalid properties with reasons
+ */
+ public function listInvalidProperties()
+ {
+ $invalidProperties = [];
+
+ if (!isset($this->container['configuration']) || null === $this->container['configuration']) {
+ $invalidProperties[] = "'configuration' can't be null";
+ }
+ if (!isset($this->container['variants']) || null === $this->container['variants']) {
+ $invalidProperties[] = "'variants' can't be null";
+ }
+
+ return $invalidProperties;
+ }
+
+ /**
+ * Validate all the properties in the model
+ * return true if all passed.
+ *
+ * @return bool True if all properties are valid
+ */
+ public function valid()
+ {
+ return 0 === count($this->listInvalidProperties());
+ }
+
+ /**
+ * Gets configuration.
+ *
+ * @return EstimateConfiguration
+ */
+ public function getConfiguration()
+ {
+ return $this->container['configuration'] ?? null;
+ }
+
+ /**
+ * Sets configuration.
+ *
+ * @param EstimateConfiguration $configuration configuration
+ *
+ * @return self
+ */
+ public function setConfiguration($configuration)
+ {
+ $this->container['configuration'] = $configuration;
+
+ return $this;
+ }
+
+ /**
+ * Gets variants.
+ *
+ * @return \Algolia\AlgoliaSearch\Model\Abtesting\AddABTestsVariant[]
+ */
+ public function getVariants()
+ {
+ return $this->container['variants'] ?? null;
+ }
+
+ /**
+ * Sets variants.
+ *
+ * @param \Algolia\AlgoliaSearch\Model\Abtesting\AddABTestsVariant[] $variants A/B test variants
+ *
+ * @return self
+ */
+ public function setVariants($variants)
+ {
+ $this->container['variants'] = $variants;
+
+ return $this;
+ }
+
+ /**
+ * Returns true if offset exists. False otherwise.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetExists($offset): bool
+ {
+ return isset($this->container[$offset]);
+ }
+
+ /**
+ * Gets offset.
+ *
+ * @param int $offset Offset
+ *
+ * @return null|mixed
+ */
+ public function offsetGet($offset): mixed
+ {
+ return $this->container[$offset] ?? null;
+ }
+
+ /**
+ * Sets value based on offset.
+ *
+ * @param null|int $offset Offset
+ * @param mixed $value Value to be set
+ */
+ public function offsetSet($offset, $value): void
+ {
+ if (is_null($offset)) {
+ $this->container[] = $value;
+ } else {
+ $this->container[$offset] = $value;
+ }
+ }
+
+ /**
+ * Unsets offset.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetUnset($offset): void
+ {
+ unset($this->container[$offset]);
+ }
+}
diff --git a/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestResponse.php b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestResponse.php
new file mode 100644
index 00000000000..e67cd690eb5
--- /dev/null
+++ b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateABTestResponse.php
@@ -0,0 +1,288 @@
+ 'int',
+ 'controlSampleSize' => 'int',
+ 'experimentSampleSize' => 'int',
+ ];
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @var string[]
+ */
+ protected static $modelFormats = [
+ 'durationDays' => 'int64',
+ 'controlSampleSize' => 'int64',
+ 'experimentSampleSize' => 'int64',
+ ];
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @var string[]
+ */
+ protected static $attributeMap = [
+ 'durationDays' => 'durationDays',
+ 'controlSampleSize' => 'controlSampleSize',
+ 'experimentSampleSize' => 'experimentSampleSize',
+ ];
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @var string[]
+ */
+ protected static $setters = [
+ 'durationDays' => 'setDurationDays',
+ 'controlSampleSize' => 'setControlSampleSize',
+ 'experimentSampleSize' => 'setExperimentSampleSize',
+ ];
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @var string[]
+ */
+ protected static $getters = [
+ 'durationDays' => 'getDurationDays',
+ 'controlSampleSize' => 'getControlSampleSize',
+ 'experimentSampleSize' => 'getExperimentSampleSize',
+ ];
+
+ /**
+ * Associative array for storing property values.
+ *
+ * @var mixed[]
+ */
+ protected $container = [];
+
+ /**
+ * Constructor.
+ *
+ * @param mixed[] $data Associated array of property values
+ */
+ public function __construct(?array $data = null)
+ {
+ if (isset($data['durationDays'])) {
+ $this->container['durationDays'] = $data['durationDays'];
+ }
+ if (isset($data['controlSampleSize'])) {
+ $this->container['controlSampleSize'] = $data['controlSampleSize'];
+ }
+ if (isset($data['experimentSampleSize'])) {
+ $this->container['experimentSampleSize'] = $data['experimentSampleSize'];
+ }
+ }
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @return array
+ */
+ public static function attributeMap()
+ {
+ return self::$attributeMap;
+ }
+
+ /**
+ * Array of property to type mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelTypes()
+ {
+ return self::$modelTypes;
+ }
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelFormats()
+ {
+ return self::$modelFormats;
+ }
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @return array
+ */
+ public static function setters()
+ {
+ return self::$setters;
+ }
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @return array
+ */
+ public static function getters()
+ {
+ return self::$getters;
+ }
+
+ /**
+ * Show all the invalid properties with reasons.
+ *
+ * @return array invalid properties with reasons
+ */
+ public function listInvalidProperties()
+ {
+ return [];
+ }
+
+ /**
+ * Validate all the properties in the model
+ * return true if all passed.
+ *
+ * @return bool True if all properties are valid
+ */
+ public function valid()
+ {
+ return 0 === count($this->listInvalidProperties());
+ }
+
+ /**
+ * Gets durationDays.
+ *
+ * @return null|int
+ */
+ public function getDurationDays()
+ {
+ return $this->container['durationDays'] ?? null;
+ }
+
+ /**
+ * Sets durationDays.
+ *
+ * @param null|int $durationDays Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ *
+ * @return self
+ */
+ public function setDurationDays($durationDays)
+ {
+ $this->container['durationDays'] = $durationDays;
+
+ return $this;
+ }
+
+ /**
+ * Gets controlSampleSize.
+ *
+ * @return null|int
+ */
+ public function getControlSampleSize()
+ {
+ return $this->container['controlSampleSize'] ?? null;
+ }
+
+ /**
+ * Sets controlSampleSize.
+ *
+ * @param null|int $controlSampleSize number of tracked searches needed to be able to detect the configured effect for the control variant
+ *
+ * @return self
+ */
+ public function setControlSampleSize($controlSampleSize)
+ {
+ $this->container['controlSampleSize'] = $controlSampleSize;
+
+ return $this;
+ }
+
+ /**
+ * Gets experimentSampleSize.
+ *
+ * @return null|int
+ */
+ public function getExperimentSampleSize()
+ {
+ return $this->container['experimentSampleSize'] ?? null;
+ }
+
+ /**
+ * Sets experimentSampleSize.
+ *
+ * @param null|int $experimentSampleSize number of tracked searches needed to be able to detect the configured effect for the experiment variant
+ *
+ * @return self
+ */
+ public function setExperimentSampleSize($experimentSampleSize)
+ {
+ $this->container['experimentSampleSize'] = $experimentSampleSize;
+
+ return $this;
+ }
+
+ /**
+ * Returns true if offset exists. False otherwise.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetExists($offset): bool
+ {
+ return isset($this->container[$offset]);
+ }
+
+ /**
+ * Gets offset.
+ *
+ * @param int $offset Offset
+ *
+ * @return null|mixed
+ */
+ public function offsetGet($offset): mixed
+ {
+ return $this->container[$offset] ?? null;
+ }
+
+ /**
+ * Sets value based on offset.
+ *
+ * @param null|int $offset Offset
+ * @param mixed $value Value to be set
+ */
+ public function offsetSet($offset, $value): void
+ {
+ if (is_null($offset)) {
+ $this->container[] = $value;
+ } else {
+ $this->container[$offset] = $value;
+ }
+ }
+
+ /**
+ * Unsets offset.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetUnset($offset): void
+ {
+ unset($this->container[$offset]);
+ }
+}
diff --git a/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateConfiguration.php b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateConfiguration.php
new file mode 100644
index 00000000000..64105672641
--- /dev/null
+++ b/clients/algoliasearch-client-php/lib/Model/Abtesting/EstimateConfiguration.php
@@ -0,0 +1,296 @@
+ '\Algolia\AlgoliaSearch\Model\Abtesting\Outliers',
+ 'emptySearch' => '\Algolia\AlgoliaSearch\Model\Abtesting\EmptySearch',
+ 'minimumDetectableEffect' => '\Algolia\AlgoliaSearch\Model\Abtesting\MinimumDetectableEffect',
+ ];
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @var string[]
+ */
+ protected static $modelFormats = [
+ 'outliers' => null,
+ 'emptySearch' => null,
+ 'minimumDetectableEffect' => null,
+ ];
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @var string[]
+ */
+ protected static $attributeMap = [
+ 'outliers' => 'outliers',
+ 'emptySearch' => 'emptySearch',
+ 'minimumDetectableEffect' => 'minimumDetectableEffect',
+ ];
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @var string[]
+ */
+ protected static $setters = [
+ 'outliers' => 'setOutliers',
+ 'emptySearch' => 'setEmptySearch',
+ 'minimumDetectableEffect' => 'setMinimumDetectableEffect',
+ ];
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @var string[]
+ */
+ protected static $getters = [
+ 'outliers' => 'getOutliers',
+ 'emptySearch' => 'getEmptySearch',
+ 'minimumDetectableEffect' => 'getMinimumDetectableEffect',
+ ];
+
+ /**
+ * Associative array for storing property values.
+ *
+ * @var mixed[]
+ */
+ protected $container = [];
+
+ /**
+ * Constructor.
+ *
+ * @param mixed[] $data Associated array of property values
+ */
+ public function __construct(?array $data = null)
+ {
+ if (isset($data['outliers'])) {
+ $this->container['outliers'] = $data['outliers'];
+ }
+ if (isset($data['emptySearch'])) {
+ $this->container['emptySearch'] = $data['emptySearch'];
+ }
+ if (isset($data['minimumDetectableEffect'])) {
+ $this->container['minimumDetectableEffect'] = $data['minimumDetectableEffect'];
+ }
+ }
+
+ /**
+ * Array of attributes where the key is the local name,
+ * and the value is the original name.
+ *
+ * @return array
+ */
+ public static function attributeMap()
+ {
+ return self::$attributeMap;
+ }
+
+ /**
+ * Array of property to type mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelTypes()
+ {
+ return self::$modelTypes;
+ }
+
+ /**
+ * Array of property to format mappings. Used for (de)serialization.
+ *
+ * @return array
+ */
+ public static function modelFormats()
+ {
+ return self::$modelFormats;
+ }
+
+ /**
+ * Array of attributes to setter functions (for deserialization of responses).
+ *
+ * @return array
+ */
+ public static function setters()
+ {
+ return self::$setters;
+ }
+
+ /**
+ * Array of attributes to getter functions (for serialization of requests).
+ *
+ * @return array
+ */
+ public static function getters()
+ {
+ return self::$getters;
+ }
+
+ /**
+ * Show all the invalid properties with reasons.
+ *
+ * @return array invalid properties with reasons
+ */
+ public function listInvalidProperties()
+ {
+ $invalidProperties = [];
+
+ if (!isset($this->container['minimumDetectableEffect']) || null === $this->container['minimumDetectableEffect']) {
+ $invalidProperties[] = "'minimumDetectableEffect' can't be null";
+ }
+
+ return $invalidProperties;
+ }
+
+ /**
+ * Validate all the properties in the model
+ * return true if all passed.
+ *
+ * @return bool True if all properties are valid
+ */
+ public function valid()
+ {
+ return 0 === count($this->listInvalidProperties());
+ }
+
+ /**
+ * Gets outliers.
+ *
+ * @return null|Outliers
+ */
+ public function getOutliers()
+ {
+ return $this->container['outliers'] ?? null;
+ }
+
+ /**
+ * Sets outliers.
+ *
+ * @param null|Outliers $outliers outliers
+ *
+ * @return self
+ */
+ public function setOutliers($outliers)
+ {
+ $this->container['outliers'] = $outliers;
+
+ return $this;
+ }
+
+ /**
+ * Gets emptySearch.
+ *
+ * @return null|EmptySearch
+ */
+ public function getEmptySearch()
+ {
+ return $this->container['emptySearch'] ?? null;
+ }
+
+ /**
+ * Sets emptySearch.
+ *
+ * @param null|EmptySearch $emptySearch emptySearch
+ *
+ * @return self
+ */
+ public function setEmptySearch($emptySearch)
+ {
+ $this->container['emptySearch'] = $emptySearch;
+
+ return $this;
+ }
+
+ /**
+ * Gets minimumDetectableEffect.
+ *
+ * @return MinimumDetectableEffect
+ */
+ public function getMinimumDetectableEffect()
+ {
+ return $this->container['minimumDetectableEffect'] ?? null;
+ }
+
+ /**
+ * Sets minimumDetectableEffect.
+ *
+ * @param MinimumDetectableEffect $minimumDetectableEffect minimumDetectableEffect
+ *
+ * @return self
+ */
+ public function setMinimumDetectableEffect($minimumDetectableEffect)
+ {
+ $this->container['minimumDetectableEffect'] = $minimumDetectableEffect;
+
+ return $this;
+ }
+
+ /**
+ * Returns true if offset exists. False otherwise.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetExists($offset): bool
+ {
+ return isset($this->container[$offset]);
+ }
+
+ /**
+ * Gets offset.
+ *
+ * @param int $offset Offset
+ *
+ * @return null|mixed
+ */
+ public function offsetGet($offset): mixed
+ {
+ return $this->container[$offset] ?? null;
+ }
+
+ /**
+ * Sets value based on offset.
+ *
+ * @param null|int $offset Offset
+ * @param mixed $value Value to be set
+ */
+ public function offsetSet($offset, $value): void
+ {
+ if (is_null($offset)) {
+ $this->container[] = $value;
+ } else {
+ $this->container[$offset] = $value;
+ }
+ }
+
+ /**
+ * Unsets offset.
+ *
+ * @param int $offset Offset
+ */
+ public function offsetUnset($offset): void
+ {
+ unset($this->container[$offset]);
+ }
+}
diff --git a/clients/algoliasearch-client-php/lib/Model/Abtesting/MinimumDetectableEffect.php b/clients/algoliasearch-client-php/lib/Model/Abtesting/MinimumDetectableEffect.php
index 936652d4597..ae79f25a1bc 100644
--- a/clients/algoliasearch-client-php/lib/Model/Abtesting/MinimumDetectableEffect.php
+++ b/clients/algoliasearch-client-php/lib/Model/Abtesting/MinimumDetectableEffect.php
@@ -23,7 +23,7 @@ class MinimumDetectableEffect extends AbstractModel implements ModelInterface, \
*/
protected static $modelTypes = [
'size' => 'float',
- 'effect' => '\Algolia\AlgoliaSearch\Model\Abtesting\Effect',
+ 'metric' => '\Algolia\AlgoliaSearch\Model\Abtesting\EffectMetric',
];
/**
@@ -33,7 +33,7 @@ class MinimumDetectableEffect extends AbstractModel implements ModelInterface, \
*/
protected static $modelFormats = [
'size' => 'double',
- 'effect' => null,
+ 'metric' => null,
];
/**
@@ -44,7 +44,7 @@ class MinimumDetectableEffect extends AbstractModel implements ModelInterface, \
*/
protected static $attributeMap = [
'size' => 'size',
- 'effect' => 'effect',
+ 'metric' => 'metric',
];
/**
@@ -54,7 +54,7 @@ class MinimumDetectableEffect extends AbstractModel implements ModelInterface, \
*/
protected static $setters = [
'size' => 'setSize',
- 'effect' => 'setEffect',
+ 'metric' => 'setMetric',
];
/**
@@ -64,7 +64,7 @@ class MinimumDetectableEffect extends AbstractModel implements ModelInterface, \
*/
protected static $getters = [
'size' => 'getSize',
- 'effect' => 'getEffect',
+ 'metric' => 'getMetric',
];
/**
@@ -84,8 +84,8 @@ public function __construct(?array $data = null)
if (isset($data['size'])) {
$this->container['size'] = $data['size'];
}
- if (isset($data['effect'])) {
- $this->container['effect'] = $data['effect'];
+ if (isset($data['metric'])) {
+ $this->container['metric'] = $data['metric'];
}
}
@@ -147,7 +147,16 @@ public static function getters()
*/
public function listInvalidProperties()
{
- return [];
+ $invalidProperties = [];
+
+ if (!isset($this->container['size']) || null === $this->container['size']) {
+ $invalidProperties[] = "'size' can't be null";
+ }
+ if (!isset($this->container['metric']) || null === $this->container['metric']) {
+ $invalidProperties[] = "'metric' can't be null";
+ }
+
+ return $invalidProperties;
}
/**
@@ -164,7 +173,7 @@ public function valid()
/**
* Gets size.
*
- * @return null|float
+ * @return float
*/
public function getSize()
{
@@ -174,7 +183,7 @@ public function getSize()
/**
* Sets size.
*
- * @param null|float $size Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
+ * @param float $size Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
*
* @return self
*/
@@ -186,25 +195,25 @@ public function setSize($size)
}
/**
- * Gets effect.
+ * Gets metric.
*
- * @return null|Effect
+ * @return EffectMetric
*/
- public function getEffect()
+ public function getMetric()
{
- return $this->container['effect'] ?? null;
+ return $this->container['metric'] ?? null;
}
/**
- * Sets effect.
+ * Sets metric.
*
- * @param null|Effect $effect effect
+ * @param EffectMetric $metric metric
*
* @return self
*/
- public function setEffect($effect)
+ public function setMetric($metric)
{
- $this->container['effect'] = $effect;
+ $this->container['metric'] = $metric;
return $this;
}
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/client.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/client.py
index 680e521a5da..5ee554d9950 100644
--- a/clients/algoliasearch-client-python/algoliasearch/abtesting/client.py
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/client.py
@@ -23,6 +23,12 @@
from algoliasearch.abtesting.models.ab_test import ABTest
from algoliasearch.abtesting.models.ab_test_response import ABTestResponse
from algoliasearch.abtesting.models.add_ab_tests_request import AddABTestsRequest
+from algoliasearch.abtesting.models.estimate_ab_test_request import (
+ EstimateABTestRequest,
+)
+from algoliasearch.abtesting.models.estimate_ab_test_response import (
+ EstimateABTestResponse,
+)
from algoliasearch.abtesting.models.list_ab_tests_response import ListABTestsResponse
from algoliasearch.abtesting.models.schedule_ab_test_response import (
ScheduleABTestResponse,
@@ -567,6 +573,63 @@ async def delete_ab_test(
resp = await self.delete_ab_test_with_http_info(id, request_options)
return resp.deserialize(ABTestResponse, resp.raw_data)
+ async def estimate_ab_test_with_http_info(
+ self,
+ estimate_ab_test_request: Union[EstimateABTestRequest, dict[str, Any]],
+ request_options: Optional[Union[dict, RequestOptions]] = None,
+ ) -> ApiResponse[str]:
+ """
+ Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+ Required API Key ACLs:
+ - analytics
+
+ :param estimate_ab_test_request: (required)
+ :type estimate_ab_test_request: EstimateABTestRequest
+ :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ :return: Returns the raw algoliasearch 'APIResponse' object.
+ """
+
+ if estimate_ab_test_request is None:
+ raise ValueError(
+ "Parameter `estimate_ab_test_request` is required when calling `estimate_ab_test`."
+ )
+
+ _data = {}
+ if estimate_ab_test_request is not None:
+ _data = estimate_ab_test_request
+
+ return await self._transporter.request(
+ verb=Verb.POST,
+ path="/2/abtests/estimate",
+ request_options=self._request_options.merge(
+ data=dumps(body_serializer(_data)),
+ user_request_options=request_options,
+ ),
+ use_read_transporter=False,
+ )
+
+ async def estimate_ab_test(
+ self,
+ estimate_ab_test_request: Union[EstimateABTestRequest, dict[str, Any]],
+ request_options: Optional[Union[dict, RequestOptions]] = None,
+ ) -> EstimateABTestResponse:
+ """
+ Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+ Required API Key ACLs:
+ - analytics
+
+ :param estimate_ab_test_request: (required)
+ :type estimate_ab_test_request: EstimateABTestRequest
+ :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ :return: Returns the deserialized response in a 'EstimateABTestResponse' result object.
+ """
+ resp = await self.estimate_ab_test_with_http_info(
+ estimate_ab_test_request, request_options
+ )
+ return resp.deserialize(EstimateABTestResponse, resp.raw_data)
+
async def get_ab_test_with_http_info(
self,
id: Annotated[StrictInt, Field(description="Unique A/B test identifier.")],
@@ -1347,6 +1410,63 @@ def delete_ab_test(
resp = self.delete_ab_test_with_http_info(id, request_options)
return resp.deserialize(ABTestResponse, resp.raw_data)
+ def estimate_ab_test_with_http_info(
+ self,
+ estimate_ab_test_request: Union[EstimateABTestRequest, dict[str, Any]],
+ request_options: Optional[Union[dict, RequestOptions]] = None,
+ ) -> ApiResponse[str]:
+ """
+ Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+ Required API Key ACLs:
+ - analytics
+
+ :param estimate_ab_test_request: (required)
+ :type estimate_ab_test_request: EstimateABTestRequest
+ :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ :return: Returns the raw algoliasearch 'APIResponse' object.
+ """
+
+ if estimate_ab_test_request is None:
+ raise ValueError(
+ "Parameter `estimate_ab_test_request` is required when calling `estimate_ab_test`."
+ )
+
+ _data = {}
+ if estimate_ab_test_request is not None:
+ _data = estimate_ab_test_request
+
+ return self._transporter.request(
+ verb=Verb.POST,
+ path="/2/abtests/estimate",
+ request_options=self._request_options.merge(
+ data=dumps(body_serializer(_data)),
+ user_request_options=request_options,
+ ),
+ use_read_transporter=False,
+ )
+
+ def estimate_ab_test(
+ self,
+ estimate_ab_test_request: Union[EstimateABTestRequest, dict[str, Any]],
+ request_options: Optional[Union[dict, RequestOptions]] = None,
+ ) -> EstimateABTestResponse:
+ """
+ Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+
+ Required API Key ACLs:
+ - analytics
+
+ :param estimate_ab_test_request: (required)
+ :type estimate_ab_test_request: EstimateABTestRequest
+ :param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ :return: Returns the deserialized response in a 'EstimateABTestResponse' result object.
+ """
+ resp = self.estimate_ab_test_with_http_info(
+ estimate_ab_test_request, request_options
+ )
+ return resp.deserialize(EstimateABTestResponse, resp.raw_data)
+
def get_ab_test_with_http_info(
self,
id: Annotated[StrictInt, Field(description="Unique A/B test identifier.")],
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect_metric.py
similarity index 89%
rename from clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect.py
rename to clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect_metric.py
index a6569231c70..f4e512c92ef 100644
--- a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect.py
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/effect_metric.py
@@ -16,7 +16,7 @@
from typing_extensions import Self
-class Effect(str, Enum):
+class EffectMetric(str, Enum):
"""
Metric for which you want to detect the smallest relative difference.
"""
@@ -34,5 +34,5 @@ class Effect(str, Enum):
@classmethod
def from_json(cls, json_str: str) -> Self:
- """Create an instance of Effect from a JSON string"""
+ """Create an instance of EffectMetric from a JSON string"""
return cls(loads(json_str))
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_request.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_request.py
new file mode 100644
index 00000000000..fb5d2aa2700
--- /dev/null
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_request.py
@@ -0,0 +1,87 @@
+# coding: utf-8
+
+"""
+Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+"""
+
+from __future__ import annotations
+
+from json import loads
+from sys import version_info
+from typing import Any, Dict, List, Optional
+
+from pydantic import BaseModel, ConfigDict
+
+if version_info >= (3, 11):
+ from typing import Self
+else:
+ from typing_extensions import Self
+
+
+from algoliasearch.abtesting.models.add_ab_tests_variant import AddABTestsVariant
+from algoliasearch.abtesting.models.estimate_configuration import EstimateConfiguration
+
+_ALIASES = {
+ "configuration": "configuration",
+ "variants": "variants",
+}
+
+
+def _alias_generator(name: str) -> str:
+ return _ALIASES.get(name, name)
+
+
+class EstimateABTestRequest(BaseModel):
+ """
+ EstimateABTestRequest
+ """
+
+ configuration: EstimateConfiguration
+ variants: List[AddABTestsVariant]
+ """ A/B test variants. """
+
+ model_config = ConfigDict(
+ use_enum_values=True,
+ populate_by_name=True,
+ validate_assignment=True,
+ protected_namespaces=(),
+ alias_generator=_alias_generator,
+ )
+
+ def to_json(self) -> str:
+ return self.model_dump_json(by_alias=True, exclude_unset=True)
+
+ @classmethod
+ def from_json(cls, json_str: str) -> Optional[Self]:
+ """Create an instance of EstimateABTestRequest from a JSON string"""
+ return cls.from_dict(loads(json_str))
+
+ def to_dict(self) -> Dict[str, Any]:
+ """Return the dictionary representation of the model using alias."""
+ return self.model_dump(
+ by_alias=True,
+ exclude_none=True,
+ exclude_unset=True,
+ )
+
+ @classmethod
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
+ """Create an instance of EstimateABTestRequest from a dict"""
+ if obj is None:
+ return None
+
+ if not isinstance(obj, dict):
+ return cls.model_validate(obj)
+
+ obj["configuration"] = (
+ EstimateConfiguration.from_dict(obj["configuration"])
+ if obj.get("configuration") is not None
+ else None
+ )
+ obj["variants"] = (
+ [AddABTestsVariant.from_dict(_item) for _item in obj["variants"]]
+ if obj.get("variants") is not None
+ else None
+ )
+
+ return cls.model_validate(obj)
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_response.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_response.py
new file mode 100644
index 00000000000..010eebb7bf1
--- /dev/null
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_ab_test_response.py
@@ -0,0 +1,77 @@
+# coding: utf-8
+
+"""
+Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+"""
+
+from __future__ import annotations
+
+from json import loads
+from sys import version_info
+from typing import Any, Dict, Optional
+
+from pydantic import BaseModel, ConfigDict
+
+if version_info >= (3, 11):
+ from typing import Self
+else:
+ from typing_extensions import Self
+
+
+_ALIASES = {
+ "duration_days": "durationDays",
+ "control_sample_size": "controlSampleSize",
+ "experiment_sample_size": "experimentSampleSize",
+}
+
+
+def _alias_generator(name: str) -> str:
+ return _ALIASES.get(name, name)
+
+
+class EstimateABTestResponse(BaseModel):
+ """
+ EstimateABTestResponse
+ """
+
+ duration_days: Optional[int] = None
+ """ Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic. """
+ control_sample_size: Optional[int] = None
+ """ Number of tracked searches needed to be able to detect the configured effect for the control variant. """
+ experiment_sample_size: Optional[int] = None
+ """ Number of tracked searches needed to be able to detect the configured effect for the experiment variant. """
+
+ model_config = ConfigDict(
+ use_enum_values=True,
+ populate_by_name=True,
+ validate_assignment=True,
+ protected_namespaces=(),
+ alias_generator=_alias_generator,
+ )
+
+ def to_json(self) -> str:
+ return self.model_dump_json(by_alias=True, exclude_unset=True)
+
+ @classmethod
+ def from_json(cls, json_str: str) -> Optional[Self]:
+ """Create an instance of EstimateABTestResponse from a JSON string"""
+ return cls.from_dict(loads(json_str))
+
+ def to_dict(self) -> Dict[str, Any]:
+ """Return the dictionary representation of the model using alias."""
+ return self.model_dump(
+ by_alias=True,
+ exclude_none=True,
+ exclude_unset=True,
+ )
+
+ @classmethod
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
+ """Create an instance of EstimateABTestResponse from a dict"""
+ if obj is None:
+ return None
+
+ if not isinstance(obj, dict):
+ return cls.model_validate(obj)
+
+ return cls.model_validate(obj)
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_configuration.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_configuration.py
new file mode 100644
index 00000000000..7f7d1862424
--- /dev/null
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/estimate_configuration.py
@@ -0,0 +1,96 @@
+# coding: utf-8
+
+"""
+Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+"""
+
+from __future__ import annotations
+
+from json import loads
+from sys import version_info
+from typing import Any, Dict, Optional
+
+from pydantic import BaseModel, ConfigDict
+
+if version_info >= (3, 11):
+ from typing import Self
+else:
+ from typing_extensions import Self
+
+
+from algoliasearch.abtesting.models.empty_search import EmptySearch
+from algoliasearch.abtesting.models.minimum_detectable_effect import (
+ MinimumDetectableEffect,
+)
+from algoliasearch.abtesting.models.outliers import Outliers
+
+_ALIASES = {
+ "outliers": "outliers",
+ "empty_search": "emptySearch",
+ "minimum_detectable_effect": "minimumDetectableEffect",
+}
+
+
+def _alias_generator(name: str) -> str:
+ return _ALIASES.get(name, name)
+
+
+class EstimateConfiguration(BaseModel):
+ """
+ A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+ """
+
+ outliers: Optional[Outliers] = None
+ empty_search: Optional[EmptySearch] = None
+ minimum_detectable_effect: MinimumDetectableEffect
+
+ model_config = ConfigDict(
+ use_enum_values=True,
+ populate_by_name=True,
+ validate_assignment=True,
+ protected_namespaces=(),
+ alias_generator=_alias_generator,
+ )
+
+ def to_json(self) -> str:
+ return self.model_dump_json(by_alias=True, exclude_unset=True)
+
+ @classmethod
+ def from_json(cls, json_str: str) -> Optional[Self]:
+ """Create an instance of EstimateConfiguration from a JSON string"""
+ return cls.from_dict(loads(json_str))
+
+ def to_dict(self) -> Dict[str, Any]:
+ """Return the dictionary representation of the model using alias."""
+ return self.model_dump(
+ by_alias=True,
+ exclude_none=True,
+ exclude_unset=True,
+ )
+
+ @classmethod
+ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
+ """Create an instance of EstimateConfiguration from a dict"""
+ if obj is None:
+ return None
+
+ if not isinstance(obj, dict):
+ return cls.model_validate(obj)
+
+ obj["outliers"] = (
+ Outliers.from_dict(obj["outliers"])
+ if obj.get("outliers") is not None
+ else None
+ )
+ obj["emptySearch"] = (
+ EmptySearch.from_dict(obj["emptySearch"])
+ if obj.get("emptySearch") is not None
+ else None
+ )
+ obj["minimumDetectableEffect"] = (
+ MinimumDetectableEffect.from_dict(obj["minimumDetectableEffect"])
+ if obj.get("minimumDetectableEffect") is not None
+ else None
+ )
+
+ return cls.model_validate(obj)
diff --git a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/minimum_detectable_effect.py b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/minimum_detectable_effect.py
index 57d8153565e..9e46fae0b3a 100644
--- a/clients/algoliasearch-client-python/algoliasearch/abtesting/models/minimum_detectable_effect.py
+++ b/clients/algoliasearch-client-python/algoliasearch/abtesting/models/minimum_detectable_effect.py
@@ -18,11 +18,11 @@
from typing_extensions import Self
-from algoliasearch.abtesting.models.effect import Effect
+from algoliasearch.abtesting.models.effect_metric import EffectMetric
_ALIASES = {
"size": "size",
- "effect": "effect",
+ "metric": "metric",
}
@@ -35,9 +35,9 @@ class MinimumDetectableEffect(BaseModel):
Configuration for the smallest difference between test variants you want to detect.
"""
- size: Optional[float] = None
+ size: float
""" Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1. """
- effect: Optional[Effect] = None
+ metric: EffectMetric
model_config = ConfigDict(
use_enum_values=True,
@@ -72,6 +72,6 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
if not isinstance(obj, dict):
return cls.model_validate(obj)
- obj["effect"] = obj.get("effect")
+ obj["metric"] = obj.get("metric")
return cls.model_validate(obj)
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/api/abtesting_client.rb b/clients/algoliasearch-client-ruby/lib/algolia/api/abtesting_client.rb
index 5869a672706..61325f31cb8 100644
--- a/clients/algoliasearch-client-ruby/lib/algolia/api/abtesting_client.rb
+++ b/clients/algoliasearch-client-ruby/lib/algolia/api/abtesting_client.rb
@@ -319,6 +319,50 @@ def delete_ab_test(id, request_options = {})
@api_client.deserialize(response.body, request_options[:debug_return_type] || "Abtesting::ABTestResponse")
end
+ # Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ #
+ # Required API Key ACLs:
+ # - analytics
+ # @param estimate_ab_test_request [EstimateABTestRequest] (required)
+ # @param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ # @return [Http::Response] the response
+ def estimate_ab_test_with_http_info(estimate_ab_test_request, request_options = {})
+ # verify the required parameter 'estimate_ab_test_request' is set
+ if @api_client.config.client_side_validation && estimate_ab_test_request.nil?
+ raise ArgumentError, "Parameter `estimate_ab_test_request` is required when calling `estimate_ab_test`."
+ end
+
+ path = "/2/abtests/estimate"
+ query_params = {}
+ query_params = query_params.merge(request_options[:query_params]) unless request_options[:query_params].nil?
+ header_params = {}
+ header_params = header_params.merge(request_options[:header_params]) unless request_options[:header_params].nil?
+
+ post_body = request_options[:debug_body] || @api_client.object_to_http_body(estimate_ab_test_request)
+
+ new_options = request_options.merge(
+ :operation => :"AbtestingClient.estimate_ab_test",
+ :header_params => header_params,
+ :query_params => query_params,
+ :body => post_body,
+ :use_read_transporter => false
+ )
+
+ @api_client.call_api(:POST, path, new_options)
+ end
+
+ # Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of an A/B test based on historical traffic.
+ #
+ # Required API Key ACLs:
+ # - analytics
+ # @param estimate_ab_test_request [EstimateABTestRequest] (required)
+ # @param request_options: The request options to send along with the query, they will be merged with the transporter base parameters (headers, query params, timeouts, etc.). (optional)
+ # @return [EstimateABTestResponse]
+ def estimate_ab_test(estimate_ab_test_request, request_options = {})
+ response = estimate_ab_test_with_http_info(estimate_ab_test_request, request_options)
+ @api_client.deserialize(response.body, request_options[:debug_return_type] || "Abtesting::EstimateABTestResponse")
+ end
+
# Retrieves the details for an A/B test by its ID.
#
# Required API Key ACLs:
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect.rb b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect_metric.rb
similarity index 86%
rename from clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect.rb
rename to clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect_metric.rb
index ea4df88eed7..6e8f6020be1 100644
--- a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect.rb
+++ b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/effect_metric.rb
@@ -5,7 +5,7 @@
module Algolia
module Abtesting
- class Effect
+ class EffectMetric
ADD_TO_CART_RATE = "addToCartRate".freeze
CLICK_THROUGH_RATE = "clickThroughRate".freeze
CONVERSION_RATE = "conversionRate".freeze
@@ -26,8 +26,8 @@ def self.build_from_hash(value)
# @param [String] The enum value in the form of the string
# @return [String] The enum value
def build_from_hash(value)
- return value if Effect.all_vars.include?(value)
- raise "Invalid ENUM value #{value} for class #Effect"
+ return value if EffectMetric.all_vars.include?(value)
+ raise "Invalid ENUM value #{value} for class #EffectMetric"
end
end
end
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_request.rb b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_request.rb
new file mode 100644
index 00000000000..ecae98565e7
--- /dev/null
+++ b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_request.rb
@@ -0,0 +1,227 @@
+# Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+require "date"
+require "time"
+
+module Algolia
+ module Abtesting
+ class EstimateABTestRequest
+ attr_accessor :configuration
+
+ # A/B test variants.
+ attr_accessor :variants
+
+ # Attribute mapping from ruby-style variable name to JSON key.
+ def self.attribute_map
+ {
+ :configuration => :configuration,
+ :variants => :variants
+ }
+ end
+
+ # Returns all the JSON keys this model knows about
+ def self.acceptable_attributes
+ attribute_map.values
+ end
+
+ # Attribute type mapping.
+ def self.types_mapping
+ {
+ :configuration => :"EstimateConfiguration",
+ :variants => :"Array"
+ }
+ end
+
+ # List of attributes with nullable: true
+ def self.openapi_nullable
+ Set.new(
+ []
+ )
+ end
+
+ # Initializes the object
+ # @param [Hash] attributes Model attributes in the form of hash
+ def initialize(attributes = {})
+ if (!attributes.is_a?(Hash))
+ raise(
+ ArgumentError,
+ "The input argument (attributes) must be a hash in `Algolia::EstimateABTestRequest` initialize method"
+ )
+ end
+
+ # check to see if the attribute exists and convert string to symbol for hash key
+ attributes = attributes.each_with_object({}) { |(k, v), h|
+ if (!self.class.attribute_map.key?(k.to_sym))
+ raise(
+ ArgumentError,
+ "`#{k}` is not a valid attribute in `Algolia::EstimateABTestRequest`. Please check the name to make sure it's valid. List of attributes: " +
+ self.class.attribute_map.keys.inspect
+ )
+ end
+
+ h[k.to_sym] = v
+ }
+
+ if attributes.key?(:configuration)
+ self.configuration = attributes[:configuration]
+ else
+ self.configuration = nil
+ end
+
+ if attributes.key?(:variants)
+ if (value = attributes[:variants]).is_a?(Array)
+ self.variants = value
+ end
+ else
+ self.variants = nil
+ end
+ end
+
+ # Checks equality by comparing each attribute.
+ # @param [Object] Object to be compared
+ def ==(other)
+ return true if self.equal?(other)
+ self.class == other.class &&
+ configuration == other.configuration &&
+ variants == other.variants
+ end
+
+ # @see the `==` method
+ # @param [Object] Object to be compared
+ def eql?(other)
+ self == other
+ end
+
+ # Calculates hash code according to all attributes.
+ # @return [Integer] Hash code
+ def hash
+ [configuration, variants].hash
+ end
+
+ # Builds the object from hash
+ # @param [Hash] attributes Model attributes in the form of hash
+ # @return [Object] Returns the model itself
+ def self.build_from_hash(attributes)
+ return nil unless attributes.is_a?(Hash)
+ attributes = attributes.transform_keys(&:to_sym)
+ transformed_hash = {}
+ types_mapping.each_pair do |key, type|
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = nil
+ elsif type =~ /\AArray<(.*)>/i
+ # check to ensure the input is an array given that the attribute
+ # is documented as an array but the input is not
+ if attributes[attribute_map[key]].is_a?(Array)
+ transformed_hash[key.to_sym] = attributes[attribute_map[key]].map { |v|
+ _deserialize(::Regexp.last_match(1), v)
+ }
+ end
+ elsif !attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = _deserialize(type, attributes[attribute_map[key]])
+ end
+ end
+
+ new(transformed_hash)
+ end
+
+ # Deserializes the data based on type
+ # @param string type Data type
+ # @param string value Value to be deserialized
+ # @return [Object] Deserialized data
+ def self._deserialize(type, value)
+ case type.to_sym
+ when :Time
+ Time.parse(value)
+ when :Date
+ Date.parse(value)
+ when :String
+ value.to_s
+ when :Integer
+ value.to_i
+ when :Float
+ value.to_f
+ when :Boolean
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
+ true
+ else
+ false
+ end
+
+ when :Object
+ # generic object (usually a Hash), return directly
+ value
+ when /\AArray<(?.+)>\z/
+ inner_type = Regexp.last_match[:inner_type]
+ value.map { |v| _deserialize(inner_type, v) }
+ when /\AHash<(?.+?), (?.+)>\z/
+ k_type = Regexp.last_match[:k_type]
+ v_type = Regexp.last_match[:v_type]
+ {}.tap do |hash|
+ value.each do |k, v|
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
+ end
+ end
+ # model
+ else
+ # models (e.g. Pet) or oneOf
+ klass = Algolia::Abtesting.const_get(type)
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass
+ .build_from_hash(value)
+ end
+ end
+
+ # Returns the string representation of the object
+ # @return [String] String presentation of the object
+ def to_s
+ to_hash.to_s
+ end
+
+ # to_body is an alias to to_hash (backward compatibility)
+ # @return [Hash] Returns the object in the form of hash
+ def to_body
+ to_hash
+ end
+
+ def to_json(*_args)
+ to_hash.to_json
+ end
+
+ # Returns the object in the form of hash
+ # @return [Hash] Returns the object in the form of hash
+ def to_hash
+ hash = {}
+ self.class.attribute_map.each_pair do |attr, param|
+ value = send(attr)
+ if value.nil?
+ is_nullable = self.class.openapi_nullable.include?(attr)
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
+ end
+
+ hash[param] = _to_hash(value)
+ end
+
+ hash
+ end
+
+ # Outputs non-array value in the form of hash
+ # For object, use to_hash. Otherwise, just return the value
+ # @param [Object] value Any valid value
+ # @return [Hash] Returns the value in the form of hash
+ def _to_hash(value)
+ if value.is_a?(Array)
+ value.compact.map { |v| _to_hash(v) }
+ elsif value.is_a?(Hash)
+ {}.tap do |hash|
+ value.each { |k, v| hash[k] = _to_hash(v) }
+ end
+ elsif value.respond_to?(:to_hash)
+ value.to_hash
+ else
+ value
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_response.rb b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_response.rb
new file mode 100644
index 00000000000..604ae8a1ff7
--- /dev/null
+++ b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_ab_test_response.rb
@@ -0,0 +1,232 @@
+# Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+require "date"
+require "time"
+
+module Algolia
+ module Abtesting
+ class EstimateABTestResponse
+ # Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value is based on historical traffic.
+ attr_accessor :duration_days
+
+ # Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ attr_accessor :control_sample_size
+
+ # Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ attr_accessor :experiment_sample_size
+
+ # Attribute mapping from ruby-style variable name to JSON key.
+ def self.attribute_map
+ {
+ :duration_days => :durationDays,
+ :control_sample_size => :controlSampleSize,
+ :experiment_sample_size => :experimentSampleSize
+ }
+ end
+
+ # Returns all the JSON keys this model knows about
+ def self.acceptable_attributes
+ attribute_map.values
+ end
+
+ # Attribute type mapping.
+ def self.types_mapping
+ {
+ :duration_days => :"Integer",
+ :control_sample_size => :"Integer",
+ :experiment_sample_size => :"Integer"
+ }
+ end
+
+ # List of attributes with nullable: true
+ def self.openapi_nullable
+ Set.new(
+ []
+ )
+ end
+
+ # Initializes the object
+ # @param [Hash] attributes Model attributes in the form of hash
+ def initialize(attributes = {})
+ if (!attributes.is_a?(Hash))
+ raise(
+ ArgumentError,
+ "The input argument (attributes) must be a hash in `Algolia::EstimateABTestResponse` initialize method"
+ )
+ end
+
+ # check to see if the attribute exists and convert string to symbol for hash key
+ attributes = attributes.each_with_object({}) { |(k, v), h|
+ if (!self.class.attribute_map.key?(k.to_sym))
+ raise(
+ ArgumentError,
+ "`#{k}` is not a valid attribute in `Algolia::EstimateABTestResponse`. Please check the name to make sure it's valid. List of attributes: " +
+ self.class.attribute_map.keys.inspect
+ )
+ end
+
+ h[k.to_sym] = v
+ }
+
+ if attributes.key?(:duration_days)
+ self.duration_days = attributes[:duration_days]
+ end
+
+ if attributes.key?(:control_sample_size)
+ self.control_sample_size = attributes[:control_sample_size]
+ end
+
+ if attributes.key?(:experiment_sample_size)
+ self.experiment_sample_size = attributes[:experiment_sample_size]
+ end
+ end
+
+ # Checks equality by comparing each attribute.
+ # @param [Object] Object to be compared
+ def ==(other)
+ return true if self.equal?(other)
+ self.class == other.class &&
+ duration_days == other.duration_days &&
+ control_sample_size == other.control_sample_size &&
+ experiment_sample_size == other.experiment_sample_size
+ end
+
+ # @see the `==` method
+ # @param [Object] Object to be compared
+ def eql?(other)
+ self == other
+ end
+
+ # Calculates hash code according to all attributes.
+ # @return [Integer] Hash code
+ def hash
+ [duration_days, control_sample_size, experiment_sample_size].hash
+ end
+
+ # Builds the object from hash
+ # @param [Hash] attributes Model attributes in the form of hash
+ # @return [Object] Returns the model itself
+ def self.build_from_hash(attributes)
+ return nil unless attributes.is_a?(Hash)
+ attributes = attributes.transform_keys(&:to_sym)
+ transformed_hash = {}
+ types_mapping.each_pair do |key, type|
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = nil
+ elsif type =~ /\AArray<(.*)>/i
+ # check to ensure the input is an array given that the attribute
+ # is documented as an array but the input is not
+ if attributes[attribute_map[key]].is_a?(Array)
+ transformed_hash[key.to_sym] = attributes[attribute_map[key]].map { |v|
+ _deserialize(::Regexp.last_match(1), v)
+ }
+ end
+ elsif !attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = _deserialize(type, attributes[attribute_map[key]])
+ end
+ end
+
+ new(transformed_hash)
+ end
+
+ # Deserializes the data based on type
+ # @param string type Data type
+ # @param string value Value to be deserialized
+ # @return [Object] Deserialized data
+ def self._deserialize(type, value)
+ case type.to_sym
+ when :Time
+ Time.parse(value)
+ when :Date
+ Date.parse(value)
+ when :String
+ value.to_s
+ when :Integer
+ value.to_i
+ when :Float
+ value.to_f
+ when :Boolean
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
+ true
+ else
+ false
+ end
+
+ when :Object
+ # generic object (usually a Hash), return directly
+ value
+ when /\AArray<(?.+)>\z/
+ inner_type = Regexp.last_match[:inner_type]
+ value.map { |v| _deserialize(inner_type, v) }
+ when /\AHash<(?.+?), (?.+)>\z/
+ k_type = Regexp.last_match[:k_type]
+ v_type = Regexp.last_match[:v_type]
+ {}.tap do |hash|
+ value.each do |k, v|
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
+ end
+ end
+ # model
+ else
+ # models (e.g. Pet) or oneOf
+ klass = Algolia::Abtesting.const_get(type)
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass
+ .build_from_hash(value)
+ end
+ end
+
+ # Returns the string representation of the object
+ # @return [String] String presentation of the object
+ def to_s
+ to_hash.to_s
+ end
+
+ # to_body is an alias to to_hash (backward compatibility)
+ # @return [Hash] Returns the object in the form of hash
+ def to_body
+ to_hash
+ end
+
+ def to_json(*_args)
+ to_hash.to_json
+ end
+
+ # Returns the object in the form of hash
+ # @return [Hash] Returns the object in the form of hash
+ def to_hash
+ hash = {}
+ self.class.attribute_map.each_pair do |attr, param|
+ value = send(attr)
+ if value.nil?
+ is_nullable = self.class.openapi_nullable.include?(attr)
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
+ end
+
+ hash[param] = _to_hash(value)
+ end
+
+ hash
+ end
+
+ # Outputs non-array value in the form of hash
+ # For object, use to_hash. Otherwise, just return the value
+ # @param [Object] value Any valid value
+ # @return [Hash] Returns the value in the form of hash
+ def _to_hash(value)
+ if value.is_a?(Array)
+ value.compact.map { |v| _to_hash(v) }
+ elsif value.is_a?(Hash)
+ {}.tap do |hash|
+ value.each { |k, v| hash[k] = _to_hash(v) }
+ end
+ elsif value.respond_to?(:to_hash)
+ value.to_hash
+ else
+ value
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_configuration.rb b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_configuration.rb
new file mode 100644
index 00000000000..ec5e1e8719f
--- /dev/null
+++ b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/estimate_configuration.rb
@@ -0,0 +1,232 @@
+# Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+require "date"
+require "time"
+
+module Algolia
+ module Abtesting
+ # A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+ class EstimateConfiguration
+ attr_accessor :outliers
+
+ attr_accessor :empty_search
+
+ attr_accessor :minimum_detectable_effect
+
+ # Attribute mapping from ruby-style variable name to JSON key.
+ def self.attribute_map
+ {
+ :outliers => :outliers,
+ :empty_search => :emptySearch,
+ :minimum_detectable_effect => :minimumDetectableEffect
+ }
+ end
+
+ # Returns all the JSON keys this model knows about
+ def self.acceptable_attributes
+ attribute_map.values
+ end
+
+ # Attribute type mapping.
+ def self.types_mapping
+ {
+ :outliers => :"Outliers",
+ :empty_search => :"EmptySearch",
+ :minimum_detectable_effect => :"MinimumDetectableEffect"
+ }
+ end
+
+ # List of attributes with nullable: true
+ def self.openapi_nullable
+ Set.new(
+ []
+ )
+ end
+
+ # Initializes the object
+ # @param [Hash] attributes Model attributes in the form of hash
+ def initialize(attributes = {})
+ if (!attributes.is_a?(Hash))
+ raise(
+ ArgumentError,
+ "The input argument (attributes) must be a hash in `Algolia::EstimateConfiguration` initialize method"
+ )
+ end
+
+ # check to see if the attribute exists and convert string to symbol for hash key
+ attributes = attributes.each_with_object({}) { |(k, v), h|
+ if (!self.class.attribute_map.key?(k.to_sym))
+ raise(
+ ArgumentError,
+ "`#{k}` is not a valid attribute in `Algolia::EstimateConfiguration`. Please check the name to make sure it's valid. List of attributes: " +
+ self.class.attribute_map.keys.inspect
+ )
+ end
+
+ h[k.to_sym] = v
+ }
+
+ if attributes.key?(:outliers)
+ self.outliers = attributes[:outliers]
+ end
+
+ if attributes.key?(:empty_search)
+ self.empty_search = attributes[:empty_search]
+ end
+
+ if attributes.key?(:minimum_detectable_effect)
+ self.minimum_detectable_effect = attributes[:minimum_detectable_effect]
+ else
+ self.minimum_detectable_effect = nil
+ end
+ end
+
+ # Checks equality by comparing each attribute.
+ # @param [Object] Object to be compared
+ def ==(other)
+ return true if self.equal?(other)
+ self.class == other.class &&
+ outliers == other.outliers &&
+ empty_search == other.empty_search &&
+ minimum_detectable_effect == other.minimum_detectable_effect
+ end
+
+ # @see the `==` method
+ # @param [Object] Object to be compared
+ def eql?(other)
+ self == other
+ end
+
+ # Calculates hash code according to all attributes.
+ # @return [Integer] Hash code
+ def hash
+ [outliers, empty_search, minimum_detectable_effect].hash
+ end
+
+ # Builds the object from hash
+ # @param [Hash] attributes Model attributes in the form of hash
+ # @return [Object] Returns the model itself
+ def self.build_from_hash(attributes)
+ return nil unless attributes.is_a?(Hash)
+ attributes = attributes.transform_keys(&:to_sym)
+ transformed_hash = {}
+ types_mapping.each_pair do |key, type|
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = nil
+ elsif type =~ /\AArray<(.*)>/i
+ # check to ensure the input is an array given that the attribute
+ # is documented as an array but the input is not
+ if attributes[attribute_map[key]].is_a?(Array)
+ transformed_hash[key.to_sym] = attributes[attribute_map[key]].map { |v|
+ _deserialize(::Regexp.last_match(1), v)
+ }
+ end
+ elsif !attributes[attribute_map[key]].nil?
+ transformed_hash[key.to_sym] = _deserialize(type, attributes[attribute_map[key]])
+ end
+ end
+
+ new(transformed_hash)
+ end
+
+ # Deserializes the data based on type
+ # @param string type Data type
+ # @param string value Value to be deserialized
+ # @return [Object] Deserialized data
+ def self._deserialize(type, value)
+ case type.to_sym
+ when :Time
+ Time.parse(value)
+ when :Date
+ Date.parse(value)
+ when :String
+ value.to_s
+ when :Integer
+ value.to_i
+ when :Float
+ value.to_f
+ when :Boolean
+ if value.to_s =~ /\A(true|t|yes|y|1)\z/i
+ true
+ else
+ false
+ end
+
+ when :Object
+ # generic object (usually a Hash), return directly
+ value
+ when /\AArray<(?.+)>\z/
+ inner_type = Regexp.last_match[:inner_type]
+ value.map { |v| _deserialize(inner_type, v) }
+ when /\AHash<(?.+?), (?.+)>\z/
+ k_type = Regexp.last_match[:k_type]
+ v_type = Regexp.last_match[:v_type]
+ {}.tap do |hash|
+ value.each do |k, v|
+ hash[_deserialize(k_type, k)] = _deserialize(v_type, v)
+ end
+ end
+ # model
+ else
+ # models (e.g. Pet) or oneOf
+ klass = Algolia::Abtesting.const_get(type)
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass
+ .build_from_hash(value)
+ end
+ end
+
+ # Returns the string representation of the object
+ # @return [String] String presentation of the object
+ def to_s
+ to_hash.to_s
+ end
+
+ # to_body is an alias to to_hash (backward compatibility)
+ # @return [Hash] Returns the object in the form of hash
+ def to_body
+ to_hash
+ end
+
+ def to_json(*_args)
+ to_hash.to_json
+ end
+
+ # Returns the object in the form of hash
+ # @return [Hash] Returns the object in the form of hash
+ def to_hash
+ hash = {}
+ self.class.attribute_map.each_pair do |attr, param|
+ value = send(attr)
+ if value.nil?
+ is_nullable = self.class.openapi_nullable.include?(attr)
+ next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
+ end
+
+ hash[param] = _to_hash(value)
+ end
+
+ hash
+ end
+
+ # Outputs non-array value in the form of hash
+ # For object, use to_hash. Otherwise, just return the value
+ # @param [Object] value Any valid value
+ # @return [Hash] Returns the value in the form of hash
+ def _to_hash(value)
+ if value.is_a?(Array)
+ value.compact.map { |v| _to_hash(v) }
+ elsif value.is_a?(Hash)
+ {}.tap do |hash|
+ value.each { |k, v| hash[k] = _to_hash(v) }
+ end
+ elsif value.respond_to?(:to_hash)
+ value.to_hash
+ else
+ value
+ end
+ end
+
+ end
+
+ end
+end
diff --git a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/minimum_detectable_effect.rb b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/minimum_detectable_effect.rb
index 24b2eb9aed7..ffb93043385 100644
--- a/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/minimum_detectable_effect.rb
+++ b/clients/algoliasearch-client-ruby/lib/algolia/models/abtesting/minimum_detectable_effect.rb
@@ -10,13 +10,13 @@ class MinimumDetectableEffect
# Smallest difference in an observable metric between variants. For example, to detect a 10% difference between variants, set this value to 0.1.
attr_accessor :size
- attr_accessor :effect
+ attr_accessor :metric
# Attribute mapping from ruby-style variable name to JSON key.
def self.attribute_map
{
:size => :size,
- :effect => :effect
+ :metric => :metric
}
end
@@ -29,7 +29,7 @@ def self.acceptable_attributes
def self.types_mapping
{
:size => :"Float",
- :effect => :"Effect"
+ :metric => :"EffectMetric"
}
end
@@ -65,10 +65,14 @@ def initialize(attributes = {})
if attributes.key?(:size)
self.size = attributes[:size]
+ else
+ self.size = nil
end
- if attributes.key?(:effect)
- self.effect = attributes[:effect]
+ if attributes.key?(:metric)
+ self.metric = attributes[:metric]
+ else
+ self.metric = nil
end
end
@@ -78,7 +82,7 @@ def ==(other)
return true if self.equal?(other)
self.class == other.class &&
size == other.size &&
- effect == other.effect
+ metric == other.metric
end
# @see the `==` method
@@ -90,7 +94,7 @@ def eql?(other)
# Calculates hash code according to all attributes.
# @return [Integer] Hash code
def hash
- [size, effect].hash
+ [size, metric].hash
end
# Builds the object from hash
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/Effect.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EffectMetric.scala
similarity index 80%
rename from clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/Effect.scala
rename to clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EffectMetric.scala
index d955999db66..ed01e15bb32 100644
--- a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/Effect.scala
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EffectMetric.scala
@@ -26,38 +26,38 @@ package algoliasearch.abtesting
import org.json4s._
-sealed trait Effect
+sealed trait EffectMetric
/** Metric for which you want to detect the smallest relative difference.
*/
-object Effect {
- case object AddToCartRate extends Effect {
+object EffectMetric {
+ case object AddToCartRate extends EffectMetric {
override def toString = "addToCartRate"
}
- case object ClickThroughRate extends Effect {
+ case object ClickThroughRate extends EffectMetric {
override def toString = "clickThroughRate"
}
- case object ConversionRate extends Effect {
+ case object ConversionRate extends EffectMetric {
override def toString = "conversionRate"
}
- case object PurchaseRate extends Effect {
+ case object PurchaseRate extends EffectMetric {
override def toString = "purchaseRate"
}
- val values: Seq[Effect] = Seq(AddToCartRate, ClickThroughRate, ConversionRate, PurchaseRate)
+ val values: Seq[EffectMetric] = Seq(AddToCartRate, ClickThroughRate, ConversionRate, PurchaseRate)
- def withName(name: String): Effect = Effect.values
+ def withName(name: String): EffectMetric = EffectMetric.values
.find(_.toString == name)
- .getOrElse(throw new MappingException(s"Unknown Effect value: $name"))
+ .getOrElse(throw new MappingException(s"Unknown EffectMetric value: $name"))
}
-class EffectSerializer
- extends CustomSerializer[Effect](_ =>
+class EffectMetricSerializer
+ extends CustomSerializer[EffectMetric](_ =>
(
{
- case JString(value) => Effect.withName(value)
+ case JString(value) => EffectMetric.withName(value)
case JNull => null
},
- { case value: Effect =>
+ { case value: EffectMetric =>
JString(value.toString)
}
)
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestRequest.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestRequest.scala
new file mode 100644
index 00000000000..9e8e12836a1
--- /dev/null
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestRequest.scala
@@ -0,0 +1,35 @@
+/** A/B Testing API The Algolia A/B Testing API lets you manage your Algolia A/B tests to optimize your search
+ * experience. ## Base URLs The base URLs for requests to the A/B testing API are: - `https://analytics.us.algolia.com`
+ * \- `https://analytics.de.algolia.com` - `https://analytics.algolia.com` (routes requests to the closest of the above
+ * servers, based on your geographical location) Use the URL that matches your [analytics
+ * region](https://dashboard.algolia.com/account/infrastructure/analytics). **All requests must use HTTPS.** ##
+ * Availability and authentication Access to the A/B testing API is available as part of the [Premium or Elevate
+ * plans](https://www.algolia.com/pricing). To authenticate your API requests, add these headers: -
+ * `x-algolia-application-id`. Your Algolia application ID. - `x-algolia-api-key`. An API key with the necessary
+ * permissions to make the request. The required access control list (ACL) to make a request is listed in each
+ * endpoint's reference. You can find your application ID and API key in the [Algolia
+ * dashboard](https://dashboard.algolia.com/account). ## Rate limits You can make up to **100 requests per minute per
+ * app** to the A/B testing API. The response includes headers with information about the limits. ## Parameters Query
+ * parameters must be [URL-encoded](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding). Non-ASCII
+ * characters must be UTF-8 encoded. Plus characters (`+`) are interpreted as spaces. ## Response status and errors The
+ * A/B testing API returns JSON responses. Since JSON doesn't guarantee any specific ordering, don't rely on the order
+ * of attributes in the API response. Successful responses return a `2xx` status. Client errors return a `4xx` status.
+ * Server errors are indicated by a `5xx` status. Error responses have a `message` property with more information. ##
+ * Version The current version of the A/B Testing API is version 2, as indicated by the `/2/` in each endpoint's URL.
+ *
+ * The version of the OpenAPI document: 2.0.0
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech Do not edit the class manually.
+ */
+package algoliasearch.abtesting
+
+/** EstimateABTestRequest
+ *
+ * @param variants
+ * A/B test variants.
+ */
+case class EstimateABTestRequest(
+ configuration: EstimateConfiguration,
+ variants: Seq[AddABTestsVariant]
+)
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestResponse.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestResponse.scala
new file mode 100644
index 00000000000..cdf2f32b672
--- /dev/null
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateABTestResponse.scala
@@ -0,0 +1,41 @@
+/** A/B Testing API The Algolia A/B Testing API lets you manage your Algolia A/B tests to optimize your search
+ * experience. ## Base URLs The base URLs for requests to the A/B testing API are: - `https://analytics.us.algolia.com`
+ * \- `https://analytics.de.algolia.com` - `https://analytics.algolia.com` (routes requests to the closest of the above
+ * servers, based on your geographical location) Use the URL that matches your [analytics
+ * region](https://dashboard.algolia.com/account/infrastructure/analytics). **All requests must use HTTPS.** ##
+ * Availability and authentication Access to the A/B testing API is available as part of the [Premium or Elevate
+ * plans](https://www.algolia.com/pricing). To authenticate your API requests, add these headers: -
+ * `x-algolia-application-id`. Your Algolia application ID. - `x-algolia-api-key`. An API key with the necessary
+ * permissions to make the request. The required access control list (ACL) to make a request is listed in each
+ * endpoint's reference. You can find your application ID and API key in the [Algolia
+ * dashboard](https://dashboard.algolia.com/account). ## Rate limits You can make up to **100 requests per minute per
+ * app** to the A/B testing API. The response includes headers with information about the limits. ## Parameters Query
+ * parameters must be [URL-encoded](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding). Non-ASCII
+ * characters must be UTF-8 encoded. Plus characters (`+`) are interpreted as spaces. ## Response status and errors The
+ * A/B testing API returns JSON responses. Since JSON doesn't guarantee any specific ordering, don't rely on the order
+ * of attributes in the API response. Successful responses return a `2xx` status. Client errors return a `4xx` status.
+ * Server errors are indicated by a `5xx` status. Error responses have a `message` property with more information. ##
+ * Version The current version of the A/B Testing API is version 2, as indicated by the `/2/` in each endpoint's URL.
+ *
+ * The version of the OpenAPI document: 2.0.0
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech Do not edit the class manually.
+ */
+package algoliasearch.abtesting
+
+/** EstimateABTestResponse
+ *
+ * @param durationDays
+ * Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This value
+ * is based on historical traffic.
+ * @param controlSampleSize
+ * Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ * @param experimentSampleSize
+ * Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ */
+case class EstimateABTestResponse(
+ durationDays: Option[Long] = scala.None,
+ controlSampleSize: Option[Long] = scala.None,
+ experimentSampleSize: Option[Long] = scala.None
+)
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateConfiguration.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateConfiguration.scala
new file mode 100644
index 00000000000..b470fdcc650
--- /dev/null
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/EstimateConfiguration.scala
@@ -0,0 +1,33 @@
+/** A/B Testing API The Algolia A/B Testing API lets you manage your Algolia A/B tests to optimize your search
+ * experience. ## Base URLs The base URLs for requests to the A/B testing API are: - `https://analytics.us.algolia.com`
+ * \- `https://analytics.de.algolia.com` - `https://analytics.algolia.com` (routes requests to the closest of the above
+ * servers, based on your geographical location) Use the URL that matches your [analytics
+ * region](https://dashboard.algolia.com/account/infrastructure/analytics). **All requests must use HTTPS.** ##
+ * Availability and authentication Access to the A/B testing API is available as part of the [Premium or Elevate
+ * plans](https://www.algolia.com/pricing). To authenticate your API requests, add these headers: -
+ * `x-algolia-application-id`. Your Algolia application ID. - `x-algolia-api-key`. An API key with the necessary
+ * permissions to make the request. The required access control list (ACL) to make a request is listed in each
+ * endpoint's reference. You can find your application ID and API key in the [Algolia
+ * dashboard](https://dashboard.algolia.com/account). ## Rate limits You can make up to **100 requests per minute per
+ * app** to the A/B testing API. The response includes headers with information about the limits. ## Parameters Query
+ * parameters must be [URL-encoded](https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding). Non-ASCII
+ * characters must be UTF-8 encoded. Plus characters (`+`) are interpreted as spaces. ## Response status and errors The
+ * A/B testing API returns JSON responses. Since JSON doesn't guarantee any specific ordering, don't rely on the order
+ * of attributes in the API response. Successful responses return a `2xx` status. Client errors return a `4xx` status.
+ * Server errors are indicated by a `5xx` status. Error responses have a `message` property with more information. ##
+ * Version The current version of the A/B Testing API is version 2, as indicated by the `/2/` in each endpoint's URL.
+ *
+ * The version of the OpenAPI document: 2.0.0
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech Do not edit the class manually.
+ */
+package algoliasearch.abtesting
+
+/** A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+ */
+case class EstimateConfiguration(
+ outliers: Option[Outliers] = scala.None,
+ emptySearch: Option[EmptySearch] = scala.None,
+ minimumDetectableEffect: MinimumDetectableEffect
+)
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/JsonSupport.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/JsonSupport.scala
index 682e4e557d4..216fcebff49 100644
--- a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/JsonSupport.scala
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/JsonSupport.scala
@@ -28,7 +28,7 @@ import org.json4s._
object JsonSupport {
private def enumSerializers: Seq[Serializer[_]] = Seq[Serializer[_]]() :+
- new EffectSerializer() :+
+ new EffectMetricSerializer() :+
new StatusSerializer()
private def oneOfsSerializers: Seq[Serializer[_]] = Seq[Serializer[_]]() :+
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/MinimumDetectableEffect.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/MinimumDetectableEffect.scala
index 67cb7fcd25f..8101906ff5c 100644
--- a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/MinimumDetectableEffect.scala
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/abtesting/MinimumDetectableEffect.scala
@@ -24,7 +24,7 @@
*/
package algoliasearch.abtesting
-import algoliasearch.abtesting.Effect._
+import algoliasearch.abtesting.EffectMetric._
/** Configuration for the smallest difference between test variants you want to detect.
*
@@ -33,6 +33,6 @@ import algoliasearch.abtesting.Effect._
* variants, set this value to 0.1.
*/
case class MinimumDetectableEffect(
- size: Option[Double] = scala.None,
- effect: Option[Effect] = scala.None
+ size: Double,
+ metric: EffectMetric
)
diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/api/AbtestingClient.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/api/AbtestingClient.scala
index 8928dd3928d..ff5fcace339 100644
--- a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/api/AbtestingClient.scala
+++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/api/AbtestingClient.scala
@@ -7,6 +7,8 @@ import algoliasearch.abtesting.ABTest
import algoliasearch.abtesting.ABTestResponse
import algoliasearch.abtesting.AddABTestsRequest
import algoliasearch.abtesting.ErrorBase
+import algoliasearch.abtesting.EstimateABTestRequest
+import algoliasearch.abtesting.EstimateABTestResponse
import algoliasearch.abtesting.ListABTestsResponse
import algoliasearch.abtesting.ScheduleABTestResponse
import algoliasearch.abtesting.ScheduleABTestsRequest
@@ -209,6 +211,29 @@ class AbtestingClient(
execute[ABTestResponse](request, requestOptions)
}
+ /** Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration of
+ * an A/B test based on historical traffic.
+ *
+ * Required API Key ACLs:
+ * - analytics
+ */
+ def estimateABTest(estimateABTestRequest: EstimateABTestRequest, requestOptions: Option[RequestOptions] = None)(
+ implicit ec: ExecutionContext
+ ): Future[EstimateABTestResponse] = Future {
+ requireNotNull(
+ estimateABTestRequest,
+ "Parameter `estimateABTestRequest` is required when calling `estimateABTest`."
+ )
+
+ val request = HttpRequest
+ .builder()
+ .withMethod("POST")
+ .withPath(s"/2/abtests/estimate")
+ .withBody(estimateABTestRequest)
+ .build()
+ execute[EstimateABTestResponse](request, requestOptions)
+ }
+
/** Retrieves the details for an A/B test by its ID.
*
* Required API Key ACLs:
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/AbtestingClient.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/AbtestingClient.swift
index 74bc5c8ac7e..7cc494fd9db 100644
--- a/clients/algoliasearch-client-swift/Sources/Abtesting/AbtestingClient.swift
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/AbtestingClient.swift
@@ -384,6 +384,53 @@ open class AbtestingClient {
)
}
+ /// - parameter estimateABTestRequest: (body)
+ /// - returns: EstimateABTestResponse
+ @available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
+ open func estimateABTest(
+ estimateABTestRequest: EstimateABTestRequest,
+ requestOptions: RequestOptions? = nil
+ ) async throws -> EstimateABTestResponse {
+ let response: Response = try await estimateABTestWithHTTPInfo(
+ estimateABTestRequest: estimateABTestRequest,
+ requestOptions: requestOptions
+ )
+
+ guard let body = response.body else {
+ throw AlgoliaError.missingData
+ }
+
+ return body
+ }
+
+ // Given the traffic percentage and the expected effect size, this endpoint estimates the sample size and duration
+ // of an A/B test based on historical traffic.
+ // Required API Key ACLs:
+ // - analytics
+ //
+ // - parameter estimateABTestRequest: (body)
+ // - returns: RequestBuilder
+
+ open func estimateABTestWithHTTPInfo(
+ estimateABTestRequest: EstimateABTestRequest,
+ requestOptions userRequestOptions: RequestOptions? = nil
+ ) async throws -> Response {
+ let resourcePath = "/2/abtests/estimate"
+ let body = estimateABTestRequest
+ let queryParameters: [String: Any?]? = nil
+
+ let nillableHeaders: [String: Any?]? = nil
+
+ let headers = APIHelper.rejectNilHeaders(nillableHeaders)
+
+ return try await self.transporter.send(
+ method: "POST",
+ path: resourcePath,
+ data: body,
+ requestOptions: RequestOptions(headers: headers, queryParameters: queryParameters) + userRequestOptions
+ )
+ }
+
/// - parameter id: (path) Unique A/B test identifier.
/// - returns: ABTest
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/Effect.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EffectMetric.swift
similarity index 81%
rename from clients/algoliasearch-client-swift/Sources/Abtesting/Models/Effect.swift
rename to clients/algoliasearch-client-swift/Sources/Abtesting/Models/EffectMetric.swift
index 81f337a6fb7..57ec40fbd4a 100644
--- a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/Effect.swift
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EffectMetric.swift
@@ -7,11 +7,11 @@ import Foundation
#endif
/// Metric for which you want to detect the smallest relative difference.
-public enum Effect: String, Codable, CaseIterable {
+public enum EffectMetric: String, Codable, CaseIterable {
case addToCartRate
case clickThroughRate
case conversionRate
case purchaseRate
}
-extension Effect: Hashable {}
+extension EffectMetric: Hashable {}
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestRequest.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestRequest.swift
new file mode 100644
index 00000000000..83d8809081d
--- /dev/null
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestRequest.swift
@@ -0,0 +1,45 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on
+// https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import Foundation
+#if canImport(Core)
+ import Core
+#endif
+
+public struct EstimateABTestRequest: Codable, JSONEncodable {
+ public var configuration: EstimateConfiguration
+ /// A/B test variants.
+ public var variants: [AddABTestsVariant]
+
+ public init(configuration: EstimateConfiguration, variants: [AddABTestsVariant]) {
+ self.configuration = configuration
+ self.variants = variants
+ }
+
+ public enum CodingKeys: String, CodingKey, CaseIterable {
+ case configuration
+ case variants
+ }
+
+ // Encodable protocol methods
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encode(self.configuration, forKey: .configuration)
+ try container.encode(self.variants, forKey: .variants)
+ }
+}
+
+extension EstimateABTestRequest: Equatable {
+ public static func ==(lhs: EstimateABTestRequest, rhs: EstimateABTestRequest) -> Bool {
+ lhs.configuration == rhs.configuration &&
+ lhs.variants == rhs.variants
+ }
+}
+
+extension EstimateABTestRequest: Hashable {
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(self.configuration.hashValue)
+ hasher.combine(self.variants.hashValue)
+ }
+}
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestResponse.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestResponse.swift
new file mode 100644
index 00000000000..fc8dee5eab1
--- /dev/null
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateABTestResponse.swift
@@ -0,0 +1,54 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on
+// https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import Foundation
+#if canImport(Core)
+ import Core
+#endif
+
+public struct EstimateABTestResponse: Codable, JSONEncodable {
+ /// Estimated number of days needed to reach the sample sizes required for detecting the configured effect. This
+ /// value is based on historical traffic.
+ public var durationDays: Int64?
+ /// Number of tracked searches needed to be able to detect the configured effect for the control variant.
+ public var controlSampleSize: Int64?
+ /// Number of tracked searches needed to be able to detect the configured effect for the experiment variant.
+ public var experimentSampleSize: Int64?
+
+ public init(durationDays: Int64? = nil, controlSampleSize: Int64? = nil, experimentSampleSize: Int64? = nil) {
+ self.durationDays = durationDays
+ self.controlSampleSize = controlSampleSize
+ self.experimentSampleSize = experimentSampleSize
+ }
+
+ public enum CodingKeys: String, CodingKey, CaseIterable {
+ case durationDays
+ case controlSampleSize
+ case experimentSampleSize
+ }
+
+ // Encodable protocol methods
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encodeIfPresent(self.durationDays, forKey: .durationDays)
+ try container.encodeIfPresent(self.controlSampleSize, forKey: .controlSampleSize)
+ try container.encodeIfPresent(self.experimentSampleSize, forKey: .experimentSampleSize)
+ }
+}
+
+extension EstimateABTestResponse: Equatable {
+ public static func ==(lhs: EstimateABTestResponse, rhs: EstimateABTestResponse) -> Bool {
+ lhs.durationDays == rhs.durationDays &&
+ lhs.controlSampleSize == rhs.controlSampleSize &&
+ lhs.experimentSampleSize == rhs.experimentSampleSize
+ }
+}
+
+extension EstimateABTestResponse: Hashable {
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(self.durationDays?.hashValue)
+ hasher.combine(self.controlSampleSize?.hashValue)
+ hasher.combine(self.experimentSampleSize?.hashValue)
+ }
+}
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateConfiguration.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateConfiguration.swift
new file mode 100644
index 00000000000..555ebb99fd1
--- /dev/null
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/EstimateConfiguration.swift
@@ -0,0 +1,55 @@
+// Code generated by OpenAPI Generator (https://openapi-generator.tech), manual changes will be lost - read more on
+// https://github.com/algolia/api-clients-automation. DO NOT EDIT.
+
+import Foundation
+#if canImport(Core)
+ import Core
+#endif
+
+/// A/B test configuration for estimating the sample size and duration using minimum detectable effect.
+public struct EstimateConfiguration: Codable, JSONEncodable {
+ public var outliers: Outliers?
+ public var emptySearch: EmptySearch?
+ public var minimumDetectableEffect: MinimumDetectableEffect
+
+ public init(
+ outliers: Outliers? = nil,
+ emptySearch: EmptySearch? = nil,
+ minimumDetectableEffect: MinimumDetectableEffect
+ ) {
+ self.outliers = outliers
+ self.emptySearch = emptySearch
+ self.minimumDetectableEffect = minimumDetectableEffect
+ }
+
+ public enum CodingKeys: String, CodingKey, CaseIterable {
+ case outliers
+ case emptySearch
+ case minimumDetectableEffect
+ }
+
+ // Encodable protocol methods
+
+ public func encode(to encoder: Encoder) throws {
+ var container = encoder.container(keyedBy: CodingKeys.self)
+ try container.encodeIfPresent(self.outliers, forKey: .outliers)
+ try container.encodeIfPresent(self.emptySearch, forKey: .emptySearch)
+ try container.encode(self.minimumDetectableEffect, forKey: .minimumDetectableEffect)
+ }
+}
+
+extension EstimateConfiguration: Equatable {
+ public static func ==(lhs: EstimateConfiguration, rhs: EstimateConfiguration) -> Bool {
+ lhs.outliers == rhs.outliers &&
+ lhs.emptySearch == rhs.emptySearch &&
+ lhs.minimumDetectableEffect == rhs.minimumDetectableEffect
+ }
+}
+
+extension EstimateConfiguration: Hashable {
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(self.outliers?.hashValue)
+ hasher.combine(self.emptySearch?.hashValue)
+ hasher.combine(self.minimumDetectableEffect.hashValue)
+ }
+}
diff --git a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/MinimumDetectableEffect.swift b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/MinimumDetectableEffect.swift
index e4621ff9727..bb4a276cd31 100644
--- a/clients/algoliasearch-client-swift/Sources/Abtesting/Models/MinimumDetectableEffect.swift
+++ b/clients/algoliasearch-client-swift/Sources/Abtesting/Models/MinimumDetectableEffect.swift
@@ -10,38 +10,38 @@ import Foundation
public struct MinimumDetectableEffect: Codable, JSONEncodable {
/// Smallest difference in an observable metric between variants. For example, to detect a 10% difference between
/// variants, set this value to 0.1.
- public var size: Double?
- public var effect: Effect?
+ public var size: Double
+ public var metric: EffectMetric
- public init(size: Double? = nil, effect: Effect? = nil) {
+ public init(size: Double, metric: EffectMetric) {
self.size = size
- self.effect = effect
+ self.metric = metric
}
public enum CodingKeys: String, CodingKey, CaseIterable {
case size
- case effect
+ case metric
}
// Encodable protocol methods
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
- try container.encodeIfPresent(self.size, forKey: .size)
- try container.encodeIfPresent(self.effect, forKey: .effect)
+ try container.encode(self.size, forKey: .size)
+ try container.encode(self.metric, forKey: .metric)
}
}
extension MinimumDetectableEffect: Equatable {
public static func ==(lhs: MinimumDetectableEffect, rhs: MinimumDetectableEffect) -> Bool {
lhs.size == rhs.size &&
- lhs.effect == rhs.effect
+ lhs.metric == rhs.metric
}
}
extension MinimumDetectableEffect: Hashable {
public func hash(into hasher: inout Hasher) {
- hasher.combine(self.size?.hashValue)
- hasher.combine(self.effect?.hashValue)
+ hasher.combine(self.size.hashValue)
+ hasher.combine(self.metric.hashValue)
}
}
diff --git a/docs/bundled/abtesting-snippets.json b/docs/bundled/abtesting-snippets.json
index 4ca2b8e07f3..55ac7bdf924 100644
--- a/docs/bundled/abtesting-snippets.json
+++ b/docs/bundled/abtesting-snippets.json
@@ -21,6 +21,9 @@
"deleteABTest": {
"default": "var response = await client.DeleteABTestAsync(42);"
},
+ "estimateABTest": {
+ "default": "var response = await client.EstimateABTestAsync(\n new EstimateABTestRequest\n {\n Configuration = new EstimateConfiguration\n {\n EmptySearch = new EmptySearch { Exclude = true },\n MinimumDetectableEffect = new MinimumDetectableEffect\n {\n Size = 0.03,\n Metric = Enum.Parse(\"ConversionRate\"),\n },\n },\n Variants = new List\n {\n new AddABTestsVariant(new AbTestsVariant { Index = \"AB_TEST_1\", TrafficPercentage = 50 }),\n new AddABTestsVariant(new AbTestsVariant { Index = \"AB_TEST_2\", TrafficPercentage = 50 }),\n },\n }\n);"
+ },
"getABTest": {
"default": "var response = await client.GetABTestAsync(42);"
},
@@ -63,6 +66,9 @@
"deleteABTest": {
"default": "response, err := client.DeleteABTest(client.NewApiDeleteABTestRequest(\n 42,\n))\nif err != nil {\n // handle the eventual error\n panic(err)\n}"
},
+ "estimateABTest": {
+ "default": "response, err := client.EstimateABTest(client.NewApiEstimateABTestRequest(\n\n abtesting.NewEmptyEstimateABTestRequest().SetConfiguration(\n abtesting.NewEmptyEstimateConfiguration().SetEmptySearch(\n abtesting.NewEmptyEmptySearch().SetExclude(true)).SetMinimumDetectableEffect(\n abtesting.NewEmptyMinimumDetectableEffect().SetSize(0.03).SetMetric(abtesting.EffectMetric(\"conversionRate\")))).SetVariants(\n []abtesting.AddABTestsVariant{*abtesting.AbTestsVariantAsAddABTestsVariant(\n abtesting.NewEmptyAbTestsVariant().SetIndex(\"AB_TEST_1\").SetTrafficPercentage(50)), *abtesting.AbTestsVariantAsAddABTestsVariant(\n abtesting.NewEmptyAbTestsVariant().SetIndex(\"AB_TEST_2\").SetTrafficPercentage(50))}),\n))\nif err != nil {\n // handle the eventual error\n panic(err)\n}"
+ },
"getABTest": {
"default": "response, err := client.GetABTest(client.NewApiGetABTestRequest(\n 42,\n))\nif err != nil {\n // handle the eventual error\n panic(err)\n}"
},
@@ -104,6 +110,9 @@
"deleteABTest": {
"default": "client.deleteABTest(42);"
},
+ "estimateABTest": {
+ "default": "client.estimateABTest(\n new EstimateABTestRequest()\n .setConfiguration(\n new EstimateConfiguration()\n .setEmptySearch(new EmptySearch().setExclude(true))\n .setMinimumDetectableEffect(new MinimumDetectableEffect().setSize(0.03).setMetric(EffectMetric.CONVERSION_RATE))\n )\n .setVariants(\n Arrays.asList(\n new AbTestsVariant().setIndex(\"AB_TEST_1\").setTrafficPercentage(50),\n new AbTestsVariant().setIndex(\"AB_TEST_2\").setTrafficPercentage(50)\n )\n )\n);"
+ },
"getABTest": {
"default": "client.getABTest(42);"
},
@@ -145,6 +154,9 @@
"deleteABTest": {
"default": "const response = await client.deleteABTest({ id: 42 });"
},
+ "estimateABTest": {
+ "default": "const response = await client.estimateABTest({\n configuration: {\n emptySearch: { exclude: true },\n minimumDetectableEffect: { size: 0.03, metric: 'conversionRate' },\n },\n variants: [\n { index: 'AB_TEST_1', trafficPercentage: 50 },\n { index: 'AB_TEST_2', trafficPercentage: 50 },\n ],\n});"
+ },
"getABTest": {
"default": "const response = await client.getABTest({ id: 42 });"
},
@@ -186,6 +198,9 @@
"deleteABTest": {
"default": "var response = client.deleteABTest(\n id = 42,\n)"
},
+ "estimateABTest": {
+ "default": "var response = client.estimateABTest(\n estimateABTestRequest = EstimateABTestRequest(\n configuration = EstimateConfiguration(\n emptySearch = EmptySearch(\n exclude = true,\n ),\n minimumDetectableEffect = MinimumDetectableEffect(\n size = 0.03,\n metric = EffectMetric.entries.first { it.value == \"conversionRate\" },\n ),\n ),\n variants = listOf(\n AbTestsVariant(\n index = \"AB_TEST_1\",\n trafficPercentage = 50,\n ),\n AbTestsVariant(\n index = \"AB_TEST_2\",\n trafficPercentage = 50,\n ),\n ),\n ),\n)"
+ },
"getABTest": {
"default": "var response = client.getABTest(\n id = 42,\n)"
},
@@ -227,6 +242,9 @@
"deleteABTest": {
"default": "$response = $client->deleteABTest(\n 42,\n);"
},
+ "estimateABTest": {
+ "default": "$response = $client->estimateABTest(\n ['configuration' => ['emptySearch' => ['exclude' => true,\n ],\n 'minimumDetectableEffect' => ['size' => 0.03,\n 'metric' => 'conversionRate',\n ],\n ],\n 'variants' => [\n ['index' => 'AB_TEST_1',\n 'trafficPercentage' => 50,\n ],\n\n ['index' => 'AB_TEST_2',\n 'trafficPercentage' => 50,\n ],\n ],\n ],\n);"
+ },
"getABTest": {
"default": "$response = $client->getABTest(\n 42,\n);"
},
@@ -268,6 +286,9 @@
"deleteABTest": {
"default": "response = client.delete_ab_test(\n id=42,\n)"
},
+ "estimateABTest": {
+ "default": "response = client.estimate_ab_test(\n estimate_ab_test_request={\n \"configuration\": {\n \"emptySearch\": {\n \"exclude\": True,\n },\n \"minimumDetectableEffect\": {\n \"size\": 0.03,\n \"metric\": \"conversionRate\",\n },\n },\n \"variants\": [\n {\n \"index\": \"AB_TEST_1\",\n \"trafficPercentage\": 50,\n },\n {\n \"index\": \"AB_TEST_2\",\n \"trafficPercentage\": 50,\n },\n ],\n },\n)"
+ },
"getABTest": {
"default": "response = client.get_ab_test(\n id=42,\n)"
},
@@ -309,6 +330,9 @@
"deleteABTest": {
"default": "response = client.delete_ab_test(42)"
},
+ "estimateABTest": {
+ "default": "response = client.estimate_ab_test(\n Algolia::Abtesting::EstimateABTestRequest.new(\n configuration: Algolia::Abtesting::EstimateConfiguration.new(\n empty_search: Algolia::Abtesting::EmptySearch.new(exclude: true),\n minimum_detectable_effect: Algolia::Abtesting::MinimumDetectableEffect.new(size: 0.03, metric: \"conversionRate\")\n ),\n variants: [\n Algolia::Abtesting::AbTestsVariant.new(index: \"AB_TEST_1\", traffic_percentage: 50),\n Algolia::Abtesting::AbTestsVariant.new(index: \"AB_TEST_2\", traffic_percentage: 50)\n ]\n )\n)"
+ },
"getABTest": {
"default": "response = client.get_ab_test(42)"
},
@@ -350,6 +374,9 @@
"deleteABTest": {
"default": "val response = client.deleteABTest(\n id = 42\n)"
},
+ "estimateABTest": {
+ "default": "val response = client.estimateABTest(\n estimateABTestRequest = EstimateABTestRequest(\n configuration = EstimateConfiguration(\n emptySearch = Some(\n EmptySearch(\n exclude = Some(true)\n )\n ),\n minimumDetectableEffect = MinimumDetectableEffect(\n size = 0.03,\n metric = EffectMetric.withName(\"conversionRate\")\n )\n ),\n variants = Seq(\n AbTestsVariant(\n index = \"AB_TEST_1\",\n trafficPercentage = 50\n ),\n AbTestsVariant(\n index = \"AB_TEST_2\",\n trafficPercentage = 50\n )\n )\n )\n)"
+ },
"getABTest": {
"default": "val response = client.getABTest(\n id = 42\n)"
},
@@ -388,6 +415,9 @@
"deleteABTest": {
"default": "let response = try await client.deleteABTest(id: 42)"
},
+ "estimateABTest": {
+ "default": "let response = try await client.estimateABTest(estimateABTestRequest: EstimateABTestRequest(\n configuration: EstimateConfiguration(\n emptySearch: EmptySearch(exclude: true),\n minimumDetectableEffect: MinimumDetectableEffect(\n size: 0.03,\n metric: EffectMetric.conversionRate\n )\n ),\n variants: [\n AddABTestsVariant.abTestsVariant(AbTestsVariant(index: \"AB_TEST_1\", trafficPercentage: 50)),\n AddABTestsVariant.abTestsVariant(AbTestsVariant(index: \"AB_TEST_2\", trafficPercentage: 50)),\n ]\n))"
+ },
"getABTest": {
"default": "let response = try await client.getABTest(id: 42)"
},
diff --git a/docs/snippets/csharp/src/Abtesting.cs b/docs/snippets/csharp/src/Abtesting.cs
index dbc1fa705f0..6dcf683d9d7 100644
--- a/docs/snippets/csharp/src/Abtesting.cs
+++ b/docs/snippets/csharp/src/Abtesting.cs
@@ -132,6 +132,43 @@ public async Task SnippetForAbtestingClientDeleteABTest()
// SEPARATOR<
}
+ ///
+ /// Snippet for the EstimateABTest method.
+ ///
+ /// estimate AB Test sample size
+ ///
+ public async Task SnippetForAbtestingClientEstimateABTest()
+ {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ var client = new AbtestingClient(
+ new AbtestingConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION")
+ );
+
+ // Call the API
+ var response = await client.EstimateABTestAsync(
+ new EstimateABTestRequest
+ {
+ Configuration = new EstimateConfiguration
+ {
+ EmptySearch = new EmptySearch { Exclude = true },
+ MinimumDetectableEffect = new MinimumDetectableEffect
+ {
+ Size = 0.03,
+ Metric = Enum.Parse("ConversionRate"),
+ },
+ },
+ Variants = new List
+ {
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_1", TrafficPercentage = 50 }),
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_2", TrafficPercentage = 50 }),
+ },
+ }
+ );
+ // >LOG
+ // SEPARATOR<
+ }
+
///
/// Snippet for the GetABTest method.
///
diff --git a/docs/snippets/go/src/abtesting.go b/docs/snippets/go/src/abtesting.go
index ad2d837bd38..8fda5adeaec 100644
--- a/docs/snippets/go/src/abtesting.go
+++ b/docs/snippets/go/src/abtesting.go
@@ -184,6 +184,42 @@ func SnippetForDeleteABTestOfAbtesting() {
print(response)
// SEPARATOR<
}
+func SnippetForEstimateABTestOfAbtesting() {
+ /*
+ Snippet for the estimateABTest method.
+
+ estimate AB Test sample size
+ */
+
+ // >SEPARATOR estimateABTest default
+ // Initialize the client with your application region, eg. abtesting.ALGOLIA_APPLICATION_REGION
+ client, err := abtesting.NewClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", abtesting.US)
+ if err != nil {
+ // The client can fail to initialize if you pass an invalid parameter.
+ panic(err)
+ }
+
+ // Call the API
+ response, err := client.EstimateABTest(client.NewApiEstimateABTestRequest(
+
+ abtesting.NewEmptyEstimateABTestRequest().SetConfiguration(
+ abtesting.NewEmptyEstimateConfiguration().SetEmptySearch(
+ abtesting.NewEmptyEmptySearch().SetExclude(true)).SetMinimumDetectableEffect(
+ abtesting.NewEmptyMinimumDetectableEffect().SetSize(0.03).SetMetric(abtesting.EffectMetric("conversionRate")))).SetVariants(
+ []abtesting.AddABTestsVariant{*abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_1").SetTrafficPercentage(50)), *abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_2").SetTrafficPercentage(50))}),
+ ))
+ if err != nil {
+ // handle the eventual error
+ panic(err)
+ }
+
+ // >LOG
+ // use the model directly
+ print(response)
+ // SEPARATOR<
+}
func SnippetForGetABTestOfAbtesting() {
/*
Snippet for the getABTest method.
diff --git a/docs/snippets/java/src/test/java/com/algolia/Abtesting.java b/docs/snippets/java/src/test/java/com/algolia/Abtesting.java
index 8b40160da11..5c80ceddc1d 100644
--- a/docs/snippets/java/src/test/java/com/algolia/Abtesting.java
+++ b/docs/snippets/java/src/test/java/com/algolia/Abtesting.java
@@ -102,6 +102,33 @@ void snippetForDeleteABTest() throws Exception {
// SEPARATOR<
}
+ // Snippet for the estimateABTest method.
+ //
+ // estimate AB Test sample size
+ void snippetForEstimateABTest() throws Exception {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ AbtestingClient client = new AbtestingClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION");
+
+ // Call the API
+ client.estimateABTest(
+ new EstimateABTestRequest()
+ .setConfiguration(
+ new EstimateConfiguration()
+ .setEmptySearch(new EmptySearch().setExclude(true))
+ .setMinimumDetectableEffect(new MinimumDetectableEffect().setSize(0.03).setMetric(EffectMetric.CONVERSION_RATE))
+ )
+ .setVariants(
+ Arrays.asList(
+ new AbTestsVariant().setIndex("AB_TEST_1").setTrafficPercentage(50),
+ new AbTestsVariant().setIndex("AB_TEST_2").setTrafficPercentage(50)
+ )
+ )
+ );
+ // >LOG
+ // SEPARATOR<
+ }
+
// Snippet for the getABTest method.
//
// getABTest
diff --git a/docs/snippets/javascript/src/abtesting.ts b/docs/snippets/javascript/src/abtesting.ts
index 54badc78d66..e13a1c659e0 100644
--- a/docs/snippets/javascript/src/abtesting.ts
+++ b/docs/snippets/javascript/src/abtesting.ts
@@ -119,6 +119,33 @@ export async function snippetForDeleteABTest(): Promise {
// SEPARATOR<
}
+// Snippet for the estimateABTest method.
+//
+// estimate AB Test sample size
+export async function snippetForEstimateABTest(): Promise {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ // Replace 'us' with your Algolia Application Region
+ const client = algoliasearch('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY').initAbtesting({ region: 'us' });
+
+ // Call the API
+ const response = await client.estimateABTest({
+ configuration: {
+ emptySearch: { exclude: true },
+ minimumDetectableEffect: { size: 0.03, metric: 'conversionRate' },
+ },
+ variants: [
+ { index: 'AB_TEST_1', trafficPercentage: 50 },
+ { index: 'AB_TEST_2', trafficPercentage: 50 },
+ ],
+ });
+
+ // >LOG
+ // use typed response
+ console.log(response);
+ // SEPARATOR<
+}
+
// Snippet for the getABTest method.
//
// getABTest
diff --git a/docs/snippets/kotlin/src/main/kotlin/com/algolia/snippets/Abtesting.kt b/docs/snippets/kotlin/src/main/kotlin/com/algolia/snippets/Abtesting.kt
index 21c6f47cd27..2ad3719a772 100644
--- a/docs/snippets/kotlin/src/main/kotlin/com/algolia/snippets/Abtesting.kt
+++ b/docs/snippets/kotlin/src/main/kotlin/com/algolia/snippets/Abtesting.kt
@@ -131,6 +131,44 @@ class SnippetAbtestingClient {
exitProcess(0)
}
+ suspend fun snippetForEstimateABTest() {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ val client = AbtestingClient(appId = "ALGOLIA_APPLICATION_ID", apiKey = "ALGOLIA_API_KEY", region = "ALGOLIA_APPLICATION_REGION")
+
+ // Call the API
+ var response = client.estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = EmptySearch(
+ exclude = true,
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.entries.first { it.value == "conversionRate" },
+ ),
+ ),
+ variants = listOf(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50,
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50,
+ ),
+ ),
+ ),
+ )
+
+ // >LOG
+ // Use the response
+ println(response)
+ // SEPARATOR<
+
+ exitProcess(0)
+ }
+
suspend fun snippetForGetABTest() {
// >SEPARATOR getABTest default
// Initialize the client
diff --git a/docs/snippets/php/src/Abtesting.php b/docs/snippets/php/src/Abtesting.php
index 7fd526d7a06..9575c35fc8f 100644
--- a/docs/snippets/php/src/Abtesting.php
+++ b/docs/snippets/php/src/Abtesting.php
@@ -154,6 +154,43 @@ public function snippetForDeleteABTest(): void
// SEPARATOR<
}
+ /**
+ * Snippet for the EstimateABTest method.
+ *
+ * estimate AB Test sample size
+ */
+ public function snippetForEstimateABTest(): void
+ {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ $client = AbtestingClient::create('ALGOLIA_APPLICATION_ID', 'ALGOLIA_API_KEY', 'ALGOLIA_APPLICATION_REGION');
+
+ // Call the API
+ $response = $client->estimateABTest(
+ ['configuration' => ['emptySearch' => ['exclude' => true,
+ ],
+ 'minimumDetectableEffect' => ['size' => 0.03,
+ 'metric' => 'conversionRate',
+ ],
+ ],
+ 'variants' => [
+ ['index' => 'AB_TEST_1',
+ 'trafficPercentage' => 50,
+ ],
+
+ ['index' => 'AB_TEST_2',
+ 'trafficPercentage' => 50,
+ ],
+ ],
+ ],
+ );
+
+ // >LOG
+ // play with the response
+ var_dump($response);
+ // SEPARATOR<
+ }
+
/**
* Snippet for the GetABTest method.
*
diff --git a/docs/snippets/python/abtesting.py b/docs/snippets/python/abtesting.py
index 7bdae35cb11..69d17f8292e 100644
--- a/docs/snippets/python/abtesting.py
+++ b/docs/snippets/python/abtesting.py
@@ -161,6 +161,50 @@ def snippet_for_delete_ab_test():
# SEPARATOR<
+def snippet_for_estimate_ab_test():
+ """
+ Snippet for the estimateABTest method.
+
+ estimate AB Test sample size
+ """
+ # >SEPARATOR estimateABTest default
+ # Initialize the client
+ # In an asynchronous context, you can use AbtestingClient instead, which exposes the exact same methods.
+ client = AbtestingClientSync(
+ "ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION"
+ )
+
+ # Call the API
+ response = client.estimate_ab_test(
+ estimate_ab_test_request={
+ "configuration": {
+ "emptySearch": {
+ "exclude": True,
+ },
+ "minimumDetectableEffect": {
+ "size": 0.03,
+ "metric": "conversionRate",
+ },
+ },
+ "variants": [
+ {
+ "index": "AB_TEST_1",
+ "trafficPercentage": 50,
+ },
+ {
+ "index": "AB_TEST_2",
+ "trafficPercentage": 50,
+ },
+ ],
+ },
+ )
+
+ # >LOG
+ # use the class directly
+ print(response)
+ # SEPARATOR<
+
+
def snippet_for_get_ab_test():
"""
Snippet for the getABTest method.
diff --git a/docs/snippets/ruby/abtesting.rb b/docs/snippets/ruby/abtesting.rb
index 1ae685ff6a6..a7d1aaba8a4 100644
--- a/docs/snippets/ruby/abtesting.rb
+++ b/docs/snippets/ruby/abtesting.rb
@@ -133,6 +133,37 @@ def snippet_for_delete_ab_test
# SEPARATOR<
end
+# Snippet for the estimateABTest method.
+#
+# estimate AB Test sample size
+def snippet_for_estimate_ab_test
+ # >SEPARATOR estimateABTest default
+ # Initialize the client
+ client = Algolia::AbtestingClient.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION")
+
+ # Call the API
+ response = client.estimate_ab_test(
+ Algolia::Abtesting::EstimateABTestRequest.new(
+ configuration: Algolia::Abtesting::EstimateConfiguration.new(
+ empty_search: Algolia::Abtesting::EmptySearch.new(exclude: true),
+ minimum_detectable_effect: Algolia::Abtesting::MinimumDetectableEffect.new(size: 0.03, metric: "conversionRate")
+ ),
+ variants: [
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_1", traffic_percentage: 50),
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_2", traffic_percentage: 50)
+ ]
+ )
+ )
+
+ # >LOG
+ # use the class directly
+ puts(response)
+
+ # print the JSON response
+ puts(response.to_json)
+ # SEPARATOR<
+end
+
# Snippet for the getABTest method.
#
# getABTest
diff --git a/docs/snippets/scala/src/main/scala/Abtesting.scala b/docs/snippets/scala/src/main/scala/Abtesting.scala
index 974a6afc334..b8199c1ebeb 100644
--- a/docs/snippets/scala/src/main/scala/Abtesting.scala
+++ b/docs/snippets/scala/src/main/scala/Abtesting.scala
@@ -174,6 +174,52 @@ class SnippetAbtestingClient {
// SEPARATOR<
}
+ /** Snippet for the estimateABTest method.
+ *
+ * estimate AB Test sample size
+ */
+ def snippetForAbtestingClientEstimateABTest(): Unit = {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ val client = AbtestingClient(
+ appId = "ALGOLIA_APPLICATION_ID",
+ apiKey = "ALGOLIA_API_KEY",
+ region = Option("ALGOLIA_APPLICATION_REGION")
+ )
+
+ // Call the API
+ val response = client.estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = Some(
+ EmptySearch(
+ exclude = Some(true)
+ )
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.withName("conversionRate")
+ )
+ ),
+ variants = Seq(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50
+ )
+ )
+ )
+ )
+
+ // >LOG
+ // Use the response
+ val value = Await.result(response, Duration(100, "sec"))
+ // SEPARATOR<
+ }
+
/** Snippet for the getABTest method.
*
* getABTest
diff --git a/docs/snippets/swift/Sources/Abtesting.swift b/docs/snippets/swift/Sources/Abtesting.swift
index 8cf7a777274..ba197b8b743 100644
--- a/docs/snippets/swift/Sources/Abtesting.swift
+++ b/docs/snippets/swift/Sources/Abtesting.swift
@@ -98,6 +98,32 @@ final class AbtestingClientSnippet {
// SEPARATOR<
}
+ /// Snippet for the estimateABTest method.
+ ///
+ /// estimate AB Test sample size
+ func snippetForEstimateABTest() async throws {
+ // >SEPARATOR estimateABTest default
+ // Initialize the client
+ let client = try AbtestingClient(appID: "ALGOLIA_APPLICATION_ID", apiKey: "ALGOLIA_API_KEY", region: .us)
+
+ // Call the API
+ let response = try await client.estimateABTest(estimateABTestRequest: EstimateABTestRequest(
+ configuration: EstimateConfiguration(
+ emptySearch: EmptySearch(exclude: true),
+ minimumDetectableEffect: MinimumDetectableEffect(
+ size: 0.03,
+ metric: EffectMetric.conversionRate
+ )
+ ),
+ variants: [
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_1", trafficPercentage: 50)),
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_2", trafficPercentage: 50)),
+ ]
+ ))
+ // >LOG
+ // SEPARATOR<
+ }
+
/// Snippet for the getABTest method.
///
/// getABTest
diff --git a/specs/bundled/abtesting.doc.yml b/specs/bundled/abtesting.doc.yml
index 587679d8ac8..910da09027a 100644
--- a/specs/bundled/abtesting.doc.yml
+++ b/specs/bundled/abtesting.doc.yml
@@ -107,8 +107,8 @@ tags:
Manage A/B tests.
- A/B tests are configurations of two indices, usually your production index
- and an index with different settings that you want to test.
+ A/B tests are configurations one or more indices, usually your production
+ index and an index with different settings that you want to test.
externalDocs:
url: https://www.algolia.com/doc/guides/ab-testing/what-is-ab-testing/
description: |
@@ -2569,6 +2569,436 @@ paths:
--header 'x-algolia-api-key: ALGOLIA_API_KEY' \
--header 'x-algolia-application-id: ALGOLIA_APPLICATION_ID' \
--data '{"name":"Custom ranking sales rank test","variants":[{"index":"delcourt_production","trafficPercentage":60,"description":"Current production index"},{"index":"delcourt_production","trafficPercentage":60,"description":"Current production index"}],"scheduledAt":"2023-06-15T15:06:44.400601Z","endAt":"2023-06-17T00:00:00Z"}'
+ /2/abtests/estimate:
+ post:
+ tags:
+ - abtest
+ operationId: estimateABTest
+ x-acl:
+ - analytics
+ summary: Estimate the sample size and duration of an A/B test
+ description: >-
+ Given the traffic percentage and the expected effect size, this endpoint
+ estimates the sample size and duration of an A/B test based on
+ historical traffic.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ title: estimateABTestRequest
+ type: object
+ additionalProperties: false
+ properties:
+ configuration:
+ title: estimateConfiguration
+ type: object
+ description: >-
+ A/B test configuration for estimating the sample size and
+ duration using minimum detectable effect.
+ properties:
+ outliers:
+ $ref: '#/components/schemas/Outliers'
+ emptySearch:
+ $ref: '#/components/schemas/EmptySearch'
+ minimumDetectableEffect:
+ $ref: '#/components/schemas/MinimumDetectableEffect'
+ required:
+ - minimumDetectableEffect
+ variants:
+ type: array
+ description: A/B test variants.
+ minItems: 2
+ maxItems: 2
+ items:
+ $ref: '#/components/schemas/AddABTestsVariant'
+ required:
+ - configuration
+ - variants
+ responses:
+ '200':
+ description: OK
+ headers:
+ x-ratelimit-limit:
+ $ref: '#/components/headers/x-ratelimit-limit'
+ x-ratelimit-remaining:
+ $ref: '#/components/headers/x-ratelimit-remaining'
+ x-ratelimit-reset:
+ $ref: '#/components/headers/x-ratelimit-reset'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EstimateABTestResponse'
+ '400':
+ $ref: '#/components/responses/BadRequest'
+ '402':
+ $ref: '#/components/responses/FeatureNotEnabled'
+ '403':
+ $ref: '#/components/responses/MethodNotAllowed'
+ '404':
+ $ref: '#/components/responses/IndexNotFound'
+ x-codeSamples:
+ - lang: csharp
+ label: C#
+ source: |
+ // Initialize the client
+ var client = new AbtestingClient(
+ new AbtestingConfig("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION")
+ );
+
+ // Call the API
+ var response = await client.EstimateABTestAsync(
+ new EstimateABTestRequest
+ {
+ Configuration = new EstimateConfiguration
+ {
+ EmptySearch = new EmptySearch { Exclude = true },
+ MinimumDetectableEffect = new MinimumDetectableEffect
+ {
+ Size = 0.03,
+ Metric = Enum.Parse("ConversionRate"),
+ },
+ },
+ Variants = new List
+ {
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_1", TrafficPercentage = 50 }),
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_2", TrafficPercentage = 50 }),
+ },
+ }
+ );
+ // >LOG
+ - lang: go
+ label: Go
+ source: >
+ // Initialize the client with your application region, eg.
+ abtesting.ALGOLIA_APPLICATION_REGION
+
+ client, err := abtesting.NewClient("ALGOLIA_APPLICATION_ID",
+ "ALGOLIA_API_KEY", abtesting.US)
+
+ if err != nil {
+ // The client can fail to initialize if you pass an invalid parameter.
+ panic(err)
+ }
+
+
+ // Call the API
+
+ response, err :=
+ client.EstimateABTest(client.NewApiEstimateABTestRequest(
+
+ abtesting.NewEmptyEstimateABTestRequest().SetConfiguration(
+ abtesting.NewEmptyEstimateConfiguration().SetEmptySearch(
+ abtesting.NewEmptyEmptySearch().SetExclude(true)).SetMinimumDetectableEffect(
+ abtesting.NewEmptyMinimumDetectableEffect().SetSize(0.03).SetMetric(abtesting.EffectMetric("conversionRate")))).SetVariants(
+ []abtesting.AddABTestsVariant{*abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_1").SetTrafficPercentage(50)), *abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_2").SetTrafficPercentage(50))}),
+ ))
+
+ if err != nil {
+ // handle the eventual error
+ panic(err)
+ }
+
+
+ // >LOG
+
+ // use the model directly
+
+ print(response)
+ - lang: java
+ label: Java
+ source: >
+ // Initialize the client
+
+ AbtestingClient client = new
+ AbtestingClient("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY",
+ "ALGOLIA_APPLICATION_REGION");
+
+
+ // Call the API
+
+ client.estimateABTest(
+ new EstimateABTestRequest()
+ .setConfiguration(
+ new EstimateConfiguration()
+ .setEmptySearch(new EmptySearch().setExclude(true))
+ .setMinimumDetectableEffect(new MinimumDetectableEffect().setSize(0.03).setMetric(EffectMetric.CONVERSION_RATE))
+ )
+ .setVariants(
+ Arrays.asList(
+ new AbTestsVariant().setIndex("AB_TEST_1").setTrafficPercentage(50),
+ new AbTestsVariant().setIndex("AB_TEST_2").setTrafficPercentage(50)
+ )
+ )
+ );
+
+ // >LOG
+ - lang: javascript
+ label: JavaScript
+ source: >
+ // Initialize the client
+
+ // Replace 'us' with your Algolia Application Region
+
+ const client = algoliasearch('ALGOLIA_APPLICATION_ID',
+ 'ALGOLIA_API_KEY').initAbtesting({ region: 'us' });
+
+
+ // Call the API
+
+ const response = await client.estimateABTest({
+ configuration: {
+ emptySearch: { exclude: true },
+ minimumDetectableEffect: { size: 0.03, metric: 'conversionRate' },
+ },
+ variants: [
+ { index: 'AB_TEST_1', trafficPercentage: 50 },
+ { index: 'AB_TEST_2', trafficPercentage: 50 },
+ ],
+ });
+
+
+ // >LOG
+
+ // use typed response
+
+ console.log(response);
+ - lang: kotlin
+ label: Kotlin
+ source: >
+ // Initialize the client
+
+ val client = AbtestingClient(appId = "ALGOLIA_APPLICATION_ID",
+ apiKey = "ALGOLIA_API_KEY", region = "ALGOLIA_APPLICATION_REGION")
+
+
+ // Call the API
+
+ var response = client.estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = EmptySearch(
+ exclude = true,
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.entries.first { it.value == "conversionRate" },
+ ),
+ ),
+ variants = listOf(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50,
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50,
+ ),
+ ),
+ ),
+ )
+
+
+ // >LOG
+
+ // Use the response
+
+ println(response)
+ - lang: php
+ label: PHP
+ source: >
+ // Initialize the client
+
+ $client = AbtestingClient::create('ALGOLIA_APPLICATION_ID',
+ 'ALGOLIA_API_KEY', 'ALGOLIA_APPLICATION_REGION');
+
+
+ // Call the API
+
+ $response = $client->estimateABTest(
+ ['configuration' => ['emptySearch' => ['exclude' => true,
+ ],
+ 'minimumDetectableEffect' => ['size' => 0.03,
+ 'metric' => 'conversionRate',
+ ],
+ ],
+ 'variants' => [
+ ['index' => 'AB_TEST_1',
+ 'trafficPercentage' => 50,
+ ],
+
+ ['index' => 'AB_TEST_2',
+ 'trafficPercentage' => 50,
+ ],
+ ],
+ ],
+ );
+
+
+ // >LOG
+
+ // play with the response
+
+ var_dump($response);
+ - lang: python
+ label: Python
+ source: >
+ # Initialize the client
+
+ # In an asynchronous context, you can use AbtestingClient instead,
+ which exposes the exact same methods.
+
+ client = AbtestingClientSync(
+ "ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION"
+ )
+
+
+ # Call the API
+
+ response = client.estimate_ab_test(
+ estimate_ab_test_request={
+ "configuration": {
+ "emptySearch": {
+ "exclude": True,
+ },
+ "minimumDetectableEffect": {
+ "size": 0.03,
+ "metric": "conversionRate",
+ },
+ },
+ "variants": [
+ {
+ "index": "AB_TEST_1",
+ "trafficPercentage": 50,
+ },
+ {
+ "index": "AB_TEST_2",
+ "trafficPercentage": 50,
+ },
+ ],
+ },
+ )
+
+
+ # >LOG
+
+ # use the class directly
+
+ print(response)
+ - lang: ruby
+ label: Ruby
+ source: >
+ # Initialize the client
+
+ client = Algolia::AbtestingClient.create("ALGOLIA_APPLICATION_ID",
+ "ALGOLIA_API_KEY", "ALGOLIA_APPLICATION_REGION")
+
+
+ # Call the API
+
+ response = client.estimate_ab_test(
+ Algolia::Abtesting::EstimateABTestRequest.new(
+ configuration: Algolia::Abtesting::EstimateConfiguration.new(
+ empty_search: Algolia::Abtesting::EmptySearch.new(exclude: true),
+ minimum_detectable_effect: Algolia::Abtesting::MinimumDetectableEffect.new(size: 0.03, metric: "conversionRate")
+ ),
+ variants: [
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_1", traffic_percentage: 50),
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_2", traffic_percentage: 50)
+ ]
+ )
+ )
+
+
+ # >LOG
+
+ # use the class directly
+
+ puts(response)
+
+
+ # print the JSON response
+
+ puts(response.to_json)
+ - lang: scala
+ label: Scala
+ source: |
+ // Initialize the client
+ val client = AbtestingClient(
+ appId = "ALGOLIA_APPLICATION_ID",
+ apiKey = "ALGOLIA_API_KEY",
+ region = Option("ALGOLIA_APPLICATION_REGION")
+ )
+
+ // Call the API
+ val response = client.estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = Some(
+ EmptySearch(
+ exclude = Some(true)
+ )
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.withName("conversionRate")
+ )
+ ),
+ variants = Seq(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50
+ )
+ )
+ )
+ )
+
+ // >LOG
+ // Use the response
+ val value = Await.result(response, Duration(100, "sec"))
+ - lang: swift
+ label: Swift
+ source: >
+ // Initialize the client
+
+ let client = try AbtestingClient(appID: "ALGOLIA_APPLICATION_ID",
+ apiKey: "ALGOLIA_API_KEY", region: .us)
+
+
+ // Call the API
+
+ let response = try await
+ client.estimateABTest(estimateABTestRequest: EstimateABTestRequest(
+ configuration: EstimateConfiguration(
+ emptySearch: EmptySearch(exclude: true),
+ minimumDetectableEffect: MinimumDetectableEffect(
+ size: 0.03,
+ metric: EffectMetric.conversionRate
+ )
+ ),
+ variants: [
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_1", trafficPercentage: 50)),
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_2", trafficPercentage: 50)),
+ ]
+ ))
+
+ // >LOG
+ - lang: cURL
+ label: curl
+ source: |-
+ curl --request POST \
+ --url https://analytics.us.algolia.com/2/abtests/estimate \
+ --header 'accept: application/json' \
+ --header 'content-type: application/json' \
+ --header 'x-algolia-api-key: ALGOLIA_API_KEY' \
+ --header 'x-algolia-application-id: ALGOLIA_APPLICATION_ID' \
+ --data '{"configuration":{"outliers":{"exclude":true},"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0,"metric":"addToCartRate"}},"variants":[{"index":"delcourt_production","trafficPercentage":60,"description":"Current production index"},{"index":"delcourt_production","trafficPercentage":60,"description":"Current production index"}]}'
components:
securitySchemes:
appId:
@@ -2920,7 +3350,7 @@ components:
exclude:
type: boolean
description: Whether to exclude empty searches when calculating A/B test results.
- Effect:
+ EffectMetric:
type: string
description: Metric for which you want to detect the smallest relative difference.
enum:
@@ -2944,8 +3374,11 @@ components:
For example, to detect a 10% difference between variants, set this
value to 0.1.
- effect:
- $ref: '#/components/schemas/Effect'
+ metric:
+ $ref: '#/components/schemas/EffectMetric'
+ required:
+ - size
+ - metric
ABTestConfiguration:
title: configuration
type: object
@@ -3150,6 +3583,31 @@ components:
$ref: '#/components/schemas/abTestScheduleID'
required:
- abTestScheduleID
+ EstimateABTestResponse:
+ type: object
+ properties:
+ durationDays:
+ type: integer
+ format: int64
+ description: >-
+ Estimated number of days needed to reach the sample sizes required
+ for detecting the configured effect. This value is based on
+ historical traffic.
+ example: 21
+ controlSampleSize:
+ type: integer
+ format: int64
+ description: >-
+ Number of tracked searches needed to be able to detect the
+ configured effect for the control variant.
+ example: 23415
+ experimentSampleSize:
+ type: integer
+ format: int64
+ description: >-
+ Number of tracked searches needed to be able to detect the
+ configured effect for the experiment variant.
+ example: 23415
responses:
BadRequest:
description: Bad request or request arguments.
diff --git a/specs/bundled/abtesting.yml b/specs/bundled/abtesting.yml
index 509cdcdf261..be3982f2b10 100644
--- a/specs/bundled/abtesting.yml
+++ b/specs/bundled/abtesting.yml
@@ -107,8 +107,8 @@ tags:
Manage A/B tests.
- A/B tests are configurations of two indices, usually your production index
- and an index with different settings that you want to test.
+ A/B tests are configurations one or more indices, usually your production
+ index and an index with different settings that you want to test.
externalDocs:
url: https://www.algolia.com/doc/guides/ab-testing/what-is-ab-testing/
description: |
@@ -517,6 +517,74 @@ paths:
$ref: '#/components/responses/MethodNotAllowed'
'404':
$ref: '#/components/responses/IndexNotFound'
+ /2/abtests/estimate:
+ post:
+ tags:
+ - abtesting
+ operationId: estimateABTest
+ x-acl:
+ - analytics
+ summary: Estimate the sample size and duration of an A/B test
+ description: >-
+ Given the traffic percentage and the expected effect size, this endpoint
+ estimates the sample size and duration of an A/B test based on
+ historical traffic.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ title: estimateABTestRequest
+ type: object
+ additionalProperties: false
+ properties:
+ configuration:
+ title: estimateConfiguration
+ type: object
+ description: >-
+ A/B test configuration for estimating the sample size and
+ duration using minimum detectable effect.
+ properties:
+ outliers:
+ $ref: '#/components/schemas/Outliers'
+ emptySearch:
+ $ref: '#/components/schemas/EmptySearch'
+ minimumDetectableEffect:
+ $ref: '#/components/schemas/MinimumDetectableEffect'
+ required:
+ - minimumDetectableEffect
+ variants:
+ type: array
+ description: A/B test variants.
+ minItems: 2
+ maxItems: 2
+ items:
+ $ref: '#/components/schemas/AddABTestsVariant'
+ required:
+ - configuration
+ - variants
+ responses:
+ '200':
+ description: OK
+ headers:
+ x-ratelimit-limit:
+ $ref: '#/components/headers/x-ratelimit-limit'
+ x-ratelimit-remaining:
+ $ref: '#/components/headers/x-ratelimit-remaining'
+ x-ratelimit-reset:
+ $ref: '#/components/headers/x-ratelimit-reset'
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EstimateABTestResponse'
+ '400':
+ $ref: '#/components/responses/BadRequest'
+ '402':
+ $ref: '#/components/responses/FeatureNotEnabled'
+ '403':
+ $ref: '#/components/responses/MethodNotAllowed'
+ '404':
+ $ref: '#/components/responses/IndexNotFound'
/setClientApiKey:
get:
x-helper: true
@@ -888,7 +956,7 @@ components:
exclude:
type: boolean
description: Whether to exclude empty searches when calculating A/B test results.
- Effect:
+ EffectMetric:
type: string
description: Metric for which you want to detect the smallest relative difference.
enum:
@@ -912,8 +980,11 @@ components:
For example, to detect a 10% difference between variants, set this
value to 0.1.
- effect:
- $ref: '#/components/schemas/Effect'
+ metric:
+ $ref: '#/components/schemas/EffectMetric'
+ required:
+ - size
+ - metric
ABTestConfiguration:
title: configuration
type: object
@@ -1118,6 +1189,31 @@ components:
$ref: '#/components/schemas/abTestScheduleID'
required:
- abTestScheduleID
+ EstimateABTestResponse:
+ type: object
+ properties:
+ durationDays:
+ type: integer
+ format: int64
+ description: >-
+ Estimated number of days needed to reach the sample sizes required
+ for detecting the configured effect. This value is based on
+ historical traffic.
+ example: 21
+ controlSampleSize:
+ type: integer
+ format: int64
+ description: >-
+ Number of tracked searches needed to be able to detect the
+ configured effect for the control variant.
+ example: 23415
+ experimentSampleSize:
+ type: integer
+ format: int64
+ description: >-
+ Number of tracked searches needed to be able to detect the
+ configured effect for the experiment variant.
+ example: 23415
responses:
BadRequest:
description: Bad request or request arguments.
diff --git a/tests/output/csharp/src/generated/e2e/Insights.test.cs b/tests/output/csharp/src/generated/e2e/Insights.test.cs
index dddfcd8738b..a24148bed62 100644
--- a/tests/output/csharp/src/generated/e2e/Insights.test.cs
+++ b/tests/output/csharp/src/generated/e2e/Insights.test.cs
@@ -63,7 +63,7 @@ public async Task PushEventsTest1()
Index = "products",
UserToken = "user-123456",
AuthenticatedUserToken = "user-123456",
- Timestamp = 1730678400000L,
+ Timestamp = 1730937600000L,
ObjectIDs = new List { "9780545139700", "9780439784542" },
QueryID = "43b15df305339e827f0ac0bdc5ebcaa7",
}
@@ -76,7 +76,7 @@ public async Task PushEventsTest1()
Index = "products",
UserToken = "user-123456",
AuthenticatedUserToken = "user-123456",
- Timestamp = 1730678400000L,
+ Timestamp = 1730937600000L,
ObjectIDs = new List { "9780545139700", "9780439784542" },
}
),
diff --git a/tests/output/csharp/src/generated/requests/Abtesting.test.cs b/tests/output/csharp/src/generated/requests/Abtesting.test.cs
index c7936d3c794..dce1f4fe6f6 100644
--- a/tests/output/csharp/src/generated/requests/Abtesting.test.cs
+++ b/tests/output/csharp/src/generated/requests/Abtesting.test.cs
@@ -554,6 +554,39 @@ public async Task DeleteABTestTest()
Assert.Null(req.Body);
}
+ [Fact(DisplayName = "estimate AB Test sample size")]
+ public async Task EstimateABTestTest()
+ {
+ await client.EstimateABTestAsync(
+ new EstimateABTestRequest
+ {
+ Configuration = new EstimateConfiguration
+ {
+ EmptySearch = new EmptySearch { Exclude = true },
+ MinimumDetectableEffect = new MinimumDetectableEffect
+ {
+ Size = 0.03,
+ Metric = Enum.Parse("ConversionRate"),
+ },
+ },
+ Variants = new List
+ {
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_1", TrafficPercentage = 50 }),
+ new AddABTestsVariant(new AbTestsVariant { Index = "AB_TEST_2", TrafficPercentage = 50 }),
+ },
+ }
+ );
+
+ var req = _echo.LastResponse;
+ Assert.Equal("/2/abtests/estimate", req.Path);
+ Assert.Equal("POST", req.Method.ToString());
+ JsonAssert.EqualOverrideDefault(
+ "{\"configuration\":{\"emptySearch\":{\"exclude\":true},\"minimumDetectableEffect\":{\"size\":0.03,\"metric\":\"conversionRate\"}},\"variants\":[{\"index\":\"AB_TEST_1\",\"trafficPercentage\":50},{\"index\":\"AB_TEST_2\",\"trafficPercentage\":50}]}",
+ req.Body,
+ new JsonDiffConfig(false)
+ );
+ }
+
[Fact(DisplayName = "getABTest")]
public async Task GetABTestTest()
{
diff --git a/tests/output/csharp/src/generated/requests/Insights.test.cs b/tests/output/csharp/src/generated/requests/Insights.test.cs
index ff71c5ea05f..d0cb7211791 100644
--- a/tests/output/csharp/src/generated/requests/Insights.test.cs
+++ b/tests/output/csharp/src/generated/requests/Insights.test.cs
@@ -580,7 +580,7 @@ await client.PushEventsAsync(
Index = "products",
UserToken = "user-123456",
AuthenticatedUserToken = "user-123456",
- Timestamp = 1730678400000L,
+ Timestamp = 1730937600000L,
ObjectIDs = new List { "9780545139700", "9780439784542" },
QueryID = "43b15df305339e827f0ac0bdc5ebcaa7",
}
@@ -593,7 +593,7 @@ await client.PushEventsAsync(
Index = "products",
UserToken = "user-123456",
AuthenticatedUserToken = "user-123456",
- Timestamp = 1730678400000L,
+ Timestamp = 1730937600000L,
ObjectIDs = new List { "9780545139700", "9780439784542" },
}
),
@@ -605,7 +605,7 @@ await client.PushEventsAsync(
Assert.Equal("/1/events", req.Path);
Assert.Equal("POST", req.Method.ToString());
JsonAssert.EqualOverrideDefault(
- "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}",
+ "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}",
req.Body,
new JsonDiffConfig(false)
);
diff --git a/tests/output/dart/test/requests/insights_test.dart b/tests/output/dart/test/requests/insights_test.dart
index c837386697e..9e97a5579f9 100644
--- a/tests/output/dart/test/requests/insights_test.dart
+++ b/tests/output/dart/test/requests/insights_test.dart
@@ -635,7 +635,7 @@ void main() {
index: "products",
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: [
"9780545139700",
"9780439784542",
@@ -648,7 +648,7 @@ void main() {
index: "products",
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: [
"9780545139700",
"9780439784542",
@@ -661,7 +661,7 @@ void main() {
expectPath(request.path, '/1/events');
expect(request.method, 'post');
expectBody(request.body,
- """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}""");
+ """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}""");
},
),
);
diff --git a/tests/output/go/tests/e2e/insights_test.go b/tests/output/go/tests/e2e/insights_test.go
index 2d02ce62880..79350fdda92 100644
--- a/tests/output/go/tests/e2e/insights_test.go
+++ b/tests/output/go/tests/e2e/insights_test.go
@@ -38,9 +38,9 @@ func TestInsightsE2E_PushEvents(t *testing.T) {
insights.NewEmptyInsightsEvents().SetEvents(
[]insights.EventsItems{*insights.ConvertedObjectIDsAfterSearchAsEventsItems(
- insights.NewEmptyConvertedObjectIDsAfterSearch().SetEventType(insights.ConversionEvent("conversion")).SetEventName("Product Purchased").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730678400000).SetObjectIDs(
+ insights.NewEmptyConvertedObjectIDsAfterSearch().SetEventType(insights.ConversionEvent("conversion")).SetEventName("Product Purchased").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730937600000).SetObjectIDs(
[]string{"9780545139700", "9780439784542"}).SetQueryID("43b15df305339e827f0ac0bdc5ebcaa7")), *insights.ViewedObjectIDsAsEventsItems(
- insights.NewEmptyViewedObjectIDs().SetEventType(insights.ViewEvent("view")).SetEventName("Product Detail Page Viewed").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730678400000).SetObjectIDs(
+ insights.NewEmptyViewedObjectIDs().SetEventType(insights.ViewEvent("view")).SetEventName("Product Detail Page Viewed").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730937600000).SetObjectIDs(
[]string{"9780545139700", "9780439784542"}))}),
))
require.NoError(t, err)
diff --git a/tests/output/go/tests/requests/abtesting_test.go b/tests/output/go/tests/requests/abtesting_test.go
index b521be59cb9..87bb2bc2a37 100644
--- a/tests/output/go/tests/requests/abtesting_test.go
+++ b/tests/output/go/tests/requests/abtesting_test.go
@@ -429,6 +429,31 @@ func TestAbtesting_DeleteABTest(t *testing.T) {
})
}
+func TestAbtesting_EstimateABTest(t *testing.T) {
+ client, echo := createAbtestingClient(t)
+ _ = echo
+
+ t.Run("estimate AB Test sample size", func(t *testing.T) {
+ _, err := client.EstimateABTest(client.NewApiEstimateABTestRequest(
+
+ abtesting.NewEmptyEstimateABTestRequest().SetConfiguration(
+ abtesting.NewEmptyEstimateConfiguration().SetEmptySearch(
+ abtesting.NewEmptyEmptySearch().SetExclude(true)).SetMinimumDetectableEffect(
+ abtesting.NewEmptyMinimumDetectableEffect().SetSize(0.03).SetMetric(abtesting.EffectMetric("conversionRate")))).SetVariants(
+ []abtesting.AddABTestsVariant{*abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_1").SetTrafficPercentage(50)), *abtesting.AbTestsVariantAsAddABTestsVariant(
+ abtesting.NewEmptyAbTestsVariant().SetIndex("AB_TEST_2").SetTrafficPercentage(50))}),
+ ))
+ require.NoError(t, err)
+
+ require.Equal(t, "/2/abtests/estimate", echo.Path)
+ require.Equal(t, "POST", echo.Method)
+
+ ja := jsonassert.New(t)
+ ja.Assertf(*echo.Body, `{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}`)
+ })
+}
+
func TestAbtesting_GetABTest(t *testing.T) {
client, echo := createAbtestingClient(t)
_ = echo
diff --git a/tests/output/go/tests/requests/insights_test.go b/tests/output/go/tests/requests/insights_test.go
index be3bbbecea0..37f00548584 100644
--- a/tests/output/go/tests/requests/insights_test.go
+++ b/tests/output/go/tests/requests/insights_test.go
@@ -433,9 +433,9 @@ func TestInsights_PushEvents(t *testing.T) {
insights.NewEmptyInsightsEvents().SetEvents(
[]insights.EventsItems{*insights.ConvertedObjectIDsAfterSearchAsEventsItems(
- insights.NewEmptyConvertedObjectIDsAfterSearch().SetEventType(insights.ConversionEvent("conversion")).SetEventName("Product Purchased").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730678400000).SetObjectIDs(
+ insights.NewEmptyConvertedObjectIDsAfterSearch().SetEventType(insights.ConversionEvent("conversion")).SetEventName("Product Purchased").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730937600000).SetObjectIDs(
[]string{"9780545139700", "9780439784542"}).SetQueryID("43b15df305339e827f0ac0bdc5ebcaa7")), *insights.ViewedObjectIDsAsEventsItems(
- insights.NewEmptyViewedObjectIDs().SetEventType(insights.ViewEvent("view")).SetEventName("Product Detail Page Viewed").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730678400000).SetObjectIDs(
+ insights.NewEmptyViewedObjectIDs().SetEventType(insights.ViewEvent("view")).SetEventName("Product Detail Page Viewed").SetIndex("products").SetUserToken("user-123456").SetAuthenticatedUserToken("user-123456").SetTimestamp(1730937600000).SetObjectIDs(
[]string{"9780545139700", "9780439784542"}))}),
))
require.NoError(t, err)
@@ -444,7 +444,7 @@ func TestInsights_PushEvents(t *testing.T) {
require.Equal(t, "POST", echo.Method)
ja := jsonassert.New(t)
- ja.Assertf(*echo.Body, `{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}`)
+ ja.Assertf(*echo.Body, `{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}`)
})
t.Run("ConvertedObjectIDsAfterSearch", func(t *testing.T) {
_, err := client.PushEvents(client.NewApiPushEventsRequest(
diff --git a/tests/output/java/src/test/java/com/algolia/e2e/Insights.test.java b/tests/output/java/src/test/java/com/algolia/e2e/Insights.test.java
index a72a7012321..01043aa5234 100644
--- a/tests/output/java/src/test/java/com/algolia/e2e/Insights.test.java
+++ b/tests/output/java/src/test/java/com/algolia/e2e/Insights.test.java
@@ -50,7 +50,7 @@ void pushEventsTest1() {
.setIndex("products")
.setUserToken("user-123456")
.setAuthenticatedUserToken("user-123456")
- .setTimestamp(1730678400000L)
+ .setTimestamp(1730937600000L)
.setObjectIDs(Arrays.asList("9780545139700", "9780439784542"))
.setQueryID("43b15df305339e827f0ac0bdc5ebcaa7"),
new ViewedObjectIDs()
@@ -59,7 +59,7 @@ void pushEventsTest1() {
.setIndex("products")
.setUserToken("user-123456")
.setAuthenticatedUserToken("user-123456")
- .setTimestamp(1730678400000L)
+ .setTimestamp(1730937600000L)
.setObjectIDs(Arrays.asList("9780545139700", "9780439784542"))
)
)
diff --git a/tests/output/java/src/test/java/com/algolia/requests/Abtesting.test.java b/tests/output/java/src/test/java/com/algolia/requests/Abtesting.test.java
index 6c931aa021f..a9cf209f54a 100644
--- a/tests/output/java/src/test/java/com/algolia/requests/Abtesting.test.java
+++ b/tests/output/java/src/test/java/com/algolia/requests/Abtesting.test.java
@@ -699,6 +699,37 @@ void deleteABTestTest() {
assertNull(req.body);
}
+ @Test
+ @DisplayName("estimate AB Test sample size")
+ void estimateABTestTest() {
+ assertDoesNotThrow(() -> {
+ client.estimateABTest(
+ new EstimateABTestRequest()
+ .setConfiguration(
+ new EstimateConfiguration()
+ .setEmptySearch(new EmptySearch().setExclude(true))
+ .setMinimumDetectableEffect(new MinimumDetectableEffect().setSize(0.03).setMetric(EffectMetric.CONVERSION_RATE))
+ )
+ .setVariants(
+ Arrays.asList(
+ new AbTestsVariant().setIndex("AB_TEST_1").setTrafficPercentage(50),
+ new AbTestsVariant().setIndex("AB_TEST_2").setTrafficPercentage(50)
+ )
+ )
+ );
+ });
+ EchoResponse req = echo.getLastResponse();
+ assertEquals("/2/abtests/estimate", req.path);
+ assertEquals("POST", req.method);
+ assertDoesNotThrow(() ->
+ JSONAssert.assertEquals(
+ "{\"configuration\":{\"emptySearch\":{\"exclude\":true},\"minimumDetectableEffect\":{\"size\":0.03,\"metric\":\"conversionRate\"}},\"variants\":[{\"index\":\"AB_TEST_1\",\"trafficPercentage\":50},{\"index\":\"AB_TEST_2\",\"trafficPercentage\":50}]}",
+ req.body,
+ JSONCompareMode.STRICT
+ )
+ );
+ }
+
@Test
@DisplayName("getABTest")
void getABTestTest() {
diff --git a/tests/output/java/src/test/java/com/algolia/requests/Insights.test.java b/tests/output/java/src/test/java/com/algolia/requests/Insights.test.java
index 967dd13aefc..bca4345f9c8 100644
--- a/tests/output/java/src/test/java/com/algolia/requests/Insights.test.java
+++ b/tests/output/java/src/test/java/com/algolia/requests/Insights.test.java
@@ -720,7 +720,7 @@ void pushEventsTest1() {
.setIndex("products")
.setUserToken("user-123456")
.setAuthenticatedUserToken("user-123456")
- .setTimestamp(1730678400000L)
+ .setTimestamp(1730937600000L)
.setObjectIDs(Arrays.asList("9780545139700", "9780439784542"))
.setQueryID("43b15df305339e827f0ac0bdc5ebcaa7"),
new ViewedObjectIDs()
@@ -729,7 +729,7 @@ void pushEventsTest1() {
.setIndex("products")
.setUserToken("user-123456")
.setAuthenticatedUserToken("user-123456")
- .setTimestamp(1730678400000L)
+ .setTimestamp(1730937600000L)
.setObjectIDs(Arrays.asList("9780545139700", "9780439784542"))
)
)
@@ -741,9 +741,9 @@ void pushEventsTest1() {
assertDoesNotThrow(() ->
JSONAssert.assertEquals(
"{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product" +
- " Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product" +
+ " Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product" +
" Detail Page" +
- " Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}",
+ " Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}",
req.body,
JSONCompareMode.STRICT
)
diff --git a/tests/output/javascript/src/e2e/insights.test.ts b/tests/output/javascript/src/e2e/insights.test.ts
index dd47f192471..f460f1e2d28 100644
--- a/tests/output/javascript/src/e2e/insights.test.ts
+++ b/tests/output/javascript/src/e2e/insights.test.ts
@@ -30,7 +30,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
queryID: '43b15df305339e827f0ac0bdc5ebcaa7',
},
@@ -40,7 +40,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
},
],
diff --git a/tests/output/javascript/src/requests/abtesting.test.ts b/tests/output/javascript/src/requests/abtesting.test.ts
index cb33067d620..fd2fa2783e8 100644
--- a/tests/output/javascript/src/requests/abtesting.test.ts
+++ b/tests/output/javascript/src/requests/abtesting.test.ts
@@ -289,6 +289,35 @@ describe('deleteABTest', () => {
});
});
+describe('estimateABTest', () => {
+ test('estimate AB Test sample size', async () => {
+ const req = (await client.estimateABTest({
+ configuration: {
+ emptySearch: { exclude: true },
+ minimumDetectableEffect: { size: 0.03, metric: 'conversionRate' },
+ },
+ variants: [
+ { index: 'AB_TEST_1', trafficPercentage: 50 },
+ { index: 'AB_TEST_2', trafficPercentage: 50 },
+ ],
+ })) as unknown as EchoResponse;
+
+ expect(req.path).toEqual('/2/abtests/estimate');
+ expect(req.method).toEqual('POST');
+ expect(req.data).toEqual({
+ configuration: {
+ emptySearch: { exclude: true },
+ minimumDetectableEffect: { size: 0.03, metric: 'conversionRate' },
+ },
+ variants: [
+ { index: 'AB_TEST_1', trafficPercentage: 50 },
+ { index: 'AB_TEST_2', trafficPercentage: 50 },
+ ],
+ });
+ expect(req.searchParams).toStrictEqual(undefined);
+ });
+});
+
describe('getABTest', () => {
test('getABTest', async () => {
const req = (await client.getABTest({ id: 42 })) as unknown as EchoResponse;
diff --git a/tests/output/javascript/src/requests/insights.test.ts b/tests/output/javascript/src/requests/insights.test.ts
index e34c5456528..72c23876035 100644
--- a/tests/output/javascript/src/requests/insights.test.ts
+++ b/tests/output/javascript/src/requests/insights.test.ts
@@ -311,7 +311,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
queryID: '43b15df305339e827f0ac0bdc5ebcaa7',
},
@@ -321,7 +321,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
},
],
@@ -337,7 +337,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
queryID: '43b15df305339e827f0ac0bdc5ebcaa7',
},
@@ -347,7 +347,7 @@ describe('pushEvents', () => {
index: 'products',
userToken: 'user-123456',
authenticatedUserToken: 'user-123456',
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
objectIDs: ['9780545139700', '9780439784542'],
},
],
diff --git a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/e2e/InsightsTest.kt b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/e2e/InsightsTest.kt
index 43de16d0f12..57170a12868 100644
--- a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/e2e/InsightsTest.kt
+++ b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/e2e/InsightsTest.kt
@@ -41,7 +41,7 @@ class InsightsTest {
index = "products",
userToken = "user-123456",
authenticatedUserToken = "user-123456",
- timestamp = 1730678400000L,
+ timestamp = 1730937600000L,
objectIDs = listOf("9780545139700", "9780439784542"),
queryID = "43b15df305339e827f0ac0bdc5ebcaa7",
),
@@ -51,7 +51,7 @@ class InsightsTest {
index = "products",
userToken = "user-123456",
authenticatedUserToken = "user-123456",
- timestamp = 1730678400000L,
+ timestamp = 1730937600000L,
objectIDs = listOf("9780545139700", "9780439784542"),
),
),
diff --git a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/AbtestingTest.kt b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/AbtestingTest.kt
index 5d514d53232..3aa073480f7 100644
--- a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/AbtestingTest.kt
+++ b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/AbtestingTest.kt
@@ -515,6 +515,44 @@ class AbtestingTest {
)
}
+ // estimateABTest
+
+ @Test
+ fun `estimate AB Test sample size`() = runTest {
+ client.runTest(
+ call = {
+ estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = EmptySearch(
+ exclude = true,
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.entries.first { it.value == "conversionRate" },
+ ),
+ ),
+ variants = listOf(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50,
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50,
+ ),
+ ),
+ ),
+ )
+ },
+ intercept = {
+ assertEquals("/2/abtests/estimate".toPathSegments(), it.url.pathSegments)
+ assertEquals(HttpMethod.parse("POST"), it.method)
+ assertJsonBody("""{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}""", it.body)
+ },
+ )
+ }
+
// getABTest
@Test
diff --git a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/InsightsTest.kt b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/InsightsTest.kt
index f6c046f4d8a..79b3e653a14 100644
--- a/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/InsightsTest.kt
+++ b/tests/output/kotlin/src/commonTest/kotlin/com/algolia/requests/InsightsTest.kt
@@ -529,7 +529,7 @@ class InsightsTest {
index = "products",
userToken = "user-123456",
authenticatedUserToken = "user-123456",
- timestamp = 1730678400000L,
+ timestamp = 1730937600000L,
objectIDs = listOf("9780545139700", "9780439784542"),
queryID = "43b15df305339e827f0ac0bdc5ebcaa7",
),
@@ -539,7 +539,7 @@ class InsightsTest {
index = "products",
userToken = "user-123456",
authenticatedUserToken = "user-123456",
- timestamp = 1730678400000L,
+ timestamp = 1730937600000L,
objectIDs = listOf("9780545139700", "9780439784542"),
),
),
@@ -549,7 +549,7 @@ class InsightsTest {
intercept = {
assertEquals("/1/events".toPathSegments(), it.url.pathSegments)
assertEquals(HttpMethod.parse("POST"), it.method)
- assertJsonBody("""{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}""", it.body)
+ assertJsonBody("""{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}""", it.body)
},
)
}
diff --git a/tests/output/php/src/e2e/InsightsTest.php b/tests/output/php/src/e2e/InsightsTest.php
index 3781bef397a..2b2697bb0c0 100644
--- a/tests/output/php/src/e2e/InsightsTest.php
+++ b/tests/output/php/src/e2e/InsightsTest.php
@@ -35,7 +35,7 @@ public function testPushEvents1(): void
'index' => 'products',
'userToken' => 'user-123456',
'authenticatedUserToken' => 'user-123456',
- 'timestamp' => 1730678400000,
+ 'timestamp' => 1730937600000,
'objectIDs' => [
'9780545139700',
@@ -49,7 +49,7 @@ public function testPushEvents1(): void
'index' => 'products',
'userToken' => 'user-123456',
'authenticatedUserToken' => 'user-123456',
- 'timestamp' => 1730678400000,
+ 'timestamp' => 1730937600000,
'objectIDs' => [
'9780545139700',
diff --git a/tests/output/php/src/requests/AbtestingTest.php b/tests/output/php/src/requests/AbtestingTest.php
index 0122df1ed68..a7e0e99db49 100644
--- a/tests/output/php/src/requests/AbtestingTest.php
+++ b/tests/output/php/src/requests/AbtestingTest.php
@@ -507,6 +507,38 @@ public function testDeleteABTest(): void
]);
}
+ #[TestDox('estimate AB Test sample size')]
+ public function testEstimateABTest(): void
+ {
+ $client = $this->getClient();
+ $client->estimateABTest(
+ ['configuration' => ['emptySearch' => ['exclude' => true,
+ ],
+ 'minimumDetectableEffect' => ['size' => 0.03,
+ 'metric' => 'conversionRate',
+ ],
+ ],
+ 'variants' => [
+ ['index' => 'AB_TEST_1',
+ 'trafficPercentage' => 50,
+ ],
+
+ ['index' => 'AB_TEST_2',
+ 'trafficPercentage' => 50,
+ ],
+ ],
+ ],
+ );
+
+ $this->assertRequests([
+ [
+ 'path' => '/2/abtests/estimate',
+ 'method' => 'POST',
+ 'body' => json_decode('{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}'),
+ ],
+ ]);
+ }
+
#[TestDox('getABTest')]
public function testGetABTest(): void
{
diff --git a/tests/output/php/src/requests/InsightsTest.php b/tests/output/php/src/requests/InsightsTest.php
index 63d39598afa..c60d423071a 100644
--- a/tests/output/php/src/requests/InsightsTest.php
+++ b/tests/output/php/src/requests/InsightsTest.php
@@ -527,7 +527,7 @@ public function testPushEvents1(): void
'index' => 'products',
'userToken' => 'user-123456',
'authenticatedUserToken' => 'user-123456',
- 'timestamp' => 1730678400000,
+ 'timestamp' => 1730937600000,
'objectIDs' => [
'9780545139700',
@@ -541,7 +541,7 @@ public function testPushEvents1(): void
'index' => 'products',
'userToken' => 'user-123456',
'authenticatedUserToken' => 'user-123456',
- 'timestamp' => 1730678400000,
+ 'timestamp' => 1730937600000,
'objectIDs' => [
'9780545139700',
@@ -556,7 +556,7 @@ public function testPushEvents1(): void
[
'path' => '/1/events',
'method' => 'POST',
- 'body' => json_decode('{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}'),
+ 'body' => json_decode('{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}'),
],
]);
}
diff --git a/tests/output/python/tests/e2e/insights_test.py b/tests/output/python/tests/e2e/insights_test.py
index 8a1781f616e..ac673d72f20 100644
--- a/tests/output/python/tests/e2e/insights_test.py
+++ b/tests/output/python/tests/e2e/insights_test.py
@@ -36,7 +36,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -49,7 +49,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -71,7 +71,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -84,7 +84,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -127,7 +127,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -140,7 +140,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -162,7 +162,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -175,7 +175,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
diff --git a/tests/output/python/tests/requests/abtesting_test.py b/tests/output/python/tests/requests/abtesting_test.py
index 56ef6a7100f..87e575bf6eb 100644
--- a/tests/output/python/tests/requests/abtesting_test.py
+++ b/tests/output/python/tests/requests/abtesting_test.py
@@ -443,6 +443,42 @@ async def test_delete_ab_test_(self):
assert _req.headers.items() >= {}.items()
assert _req.data is None
+ async def test_estimate_ab_test_(self):
+ """
+ estimate AB Test sample size
+ """
+ _req = await self._client.estimate_ab_test_with_http_info(
+ estimate_ab_test_request={
+ "configuration": {
+ "emptySearch": {
+ "exclude": True,
+ },
+ "minimumDetectableEffect": {
+ "size": 0.03,
+ "metric": "conversionRate",
+ },
+ },
+ "variants": [
+ {
+ "index": "AB_TEST_1",
+ "trafficPercentage": 50,
+ },
+ {
+ "index": "AB_TEST_2",
+ "trafficPercentage": 50,
+ },
+ ],
+ },
+ )
+
+ assert _req.path == "/2/abtests/estimate"
+ assert _req.verb == "POST"
+ assert _req.query_parameters.items() == {}.items()
+ assert _req.headers.items() >= {}.items()
+ assert loads(_req.data) == loads(
+ """{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}"""
+ )
+
async def test_get_ab_test_(self):
"""
getABTest
@@ -974,6 +1010,42 @@ def test_delete_ab_test_(self):
assert _req.headers.items() >= {}.items()
assert _req.data is None
+ def test_estimate_ab_test_(self):
+ """
+ estimate AB Test sample size
+ """
+ _req = self._client.estimate_ab_test_with_http_info(
+ estimate_ab_test_request={
+ "configuration": {
+ "emptySearch": {
+ "exclude": True,
+ },
+ "minimumDetectableEffect": {
+ "size": 0.03,
+ "metric": "conversionRate",
+ },
+ },
+ "variants": [
+ {
+ "index": "AB_TEST_1",
+ "trafficPercentage": 50,
+ },
+ {
+ "index": "AB_TEST_2",
+ "trafficPercentage": 50,
+ },
+ ],
+ },
+ )
+
+ assert _req.path == "/2/abtests/estimate"
+ assert _req.verb == "POST"
+ assert _req.query_parameters.items() == {}.items()
+ assert _req.headers.items() >= {}.items()
+ assert loads(_req.data) == loads(
+ """{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}"""
+ )
+
def test_get_ab_test_(self):
"""
getABTest
diff --git a/tests/output/python/tests/requests/insights_test.py b/tests/output/python/tests/requests/insights_test.py
index f0fa8da570d..f2ad7026911 100644
--- a/tests/output/python/tests/requests/insights_test.py
+++ b/tests/output/python/tests/requests/insights_test.py
@@ -463,7 +463,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -476,7 +476,7 @@ async def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -491,7 +491,7 @@ async def test_push_events_1(self):
assert _req.query_parameters.items() == {}.items()
assert _req.headers.items() >= {}.items()
assert loads(_req.data) == loads(
- """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}"""
+ """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}"""
)
async def test_push_events_2(self):
@@ -1060,7 +1060,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -1073,7 +1073,7 @@ def test_push_events_1(self):
"index": "products",
"userToken": "user-123456",
"authenticatedUserToken": "user-123456",
- "timestamp": 1730678400000,
+ "timestamp": 1730937600000,
"objectIDs": [
"9780545139700",
"9780439784542",
@@ -1088,7 +1088,7 @@ def test_push_events_1(self):
assert _req.query_parameters.items() == {}.items()
assert _req.headers.items() >= {}.items()
assert loads(_req.data) == loads(
- """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}"""
+ """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}"""
)
def test_push_events_2(self):
diff --git a/tests/output/ruby/test/e2e/insights_test.rb b/tests/output/ruby/test/e2e/insights_test.rb
index 68b2d30e46b..82ae604d220 100644
--- a/tests/output/ruby/test/e2e/insights_test.rb
+++ b/tests/output/ruby/test/e2e/insights_test.rb
@@ -27,7 +27,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"],
query_id: "43b15df305339e827f0ac0bdc5ebcaa7"
),
@@ -37,7 +37,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"]
)
]
@@ -54,7 +54,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"],
query_id: "43b15df305339e827f0ac0bdc5ebcaa7"
),
@@ -64,7 +64,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"]
)
]
diff --git a/tests/output/ruby/test/requests/abtesting_test.rb b/tests/output/ruby/test/requests/abtesting_test.rb
index 60c27d44564..3bfb9738ca9 100644
--- a/tests/output/ruby/test/requests/abtesting_test.rb
+++ b/tests/output/ruby/test/requests/abtesting_test.rb
@@ -319,6 +319,36 @@ def test_delete_ab_test
assert(req.body.nil?, "body is not nil")
end
+ # estimate AB Test sample size
+ def test_estimate_ab_test
+ req = @client.estimate_ab_test_with_http_info(
+ Algolia::Abtesting::EstimateABTestRequest.new(
+ configuration: Algolia::Abtesting::EstimateConfiguration.new(
+ empty_search: Algolia::Abtesting::EmptySearch.new(exclude: true),
+ minimum_detectable_effect: Algolia::Abtesting::MinimumDetectableEffect.new(
+ size: 0.03,
+ metric: "conversionRate"
+ )
+ ),
+ variants: [
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_1", traffic_percentage: 50),
+ Algolia::Abtesting::AbTestsVariant.new(index: "AB_TEST_2", traffic_percentage: 50)
+ ]
+ )
+ )
+
+ assert_equal(:post, req.method)
+ assert_equal("/2/abtests/estimate", req.path)
+ assert_equal({}.to_a, req.query_params.to_a)
+ assert(({}.to_a - req.headers.to_a).empty?, req.headers.to_s)
+ assert_equal(
+ JSON.parse(
+ "{\"configuration\":{\"emptySearch\":{\"exclude\":true},\"minimumDetectableEffect\":{\"size\":0.03,\"metric\":\"conversionRate\"}},\"variants\":[{\"index\":\"AB_TEST_1\",\"trafficPercentage\":50},{\"index\":\"AB_TEST_2\",\"trafficPercentage\":50}]}"
+ ),
+ JSON.parse(req.body)
+ )
+ end
+
# getABTest
def test_get_ab_test
req = @client.get_ab_test_with_http_info(42)
diff --git a/tests/output/ruby/test/requests/insights_test.rb b/tests/output/ruby/test/requests/insights_test.rb
index 77649a4afa1..aef1948f658 100644
--- a/tests/output/ruby/test/requests/insights_test.rb
+++ b/tests/output/ruby/test/requests/insights_test.rb
@@ -337,7 +337,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"],
query_id: "43b15df305339e827f0ac0bdc5ebcaa7"
),
@@ -347,7 +347,7 @@ def test_push_events1
index: "products",
user_token: "user-123456",
authenticated_user_token: "user-123456",
- timestamp: 1730678400000,
+ timestamp: 1730937600000,
object_ids: ["9780545139700", "9780439784542"]
)
]
@@ -360,7 +360,7 @@ def test_push_events1
assert(({}.to_a - req.headers.to_a).empty?, req.headers.to_s)
assert_equal(
JSON.parse(
- "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}"
+ "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}"
),
JSON.parse(req.body)
)
diff --git a/tests/output/scala/src/test/scala/algoliasearch/e2e/InsightsTest.scala b/tests/output/scala/src/test/scala/algoliasearch/e2e/InsightsTest.scala
index 1eb139e5856..63158573128 100644
--- a/tests/output/scala/src/test/scala/algoliasearch/e2e/InsightsTest.scala
+++ b/tests/output/scala/src/test/scala/algoliasearch/e2e/InsightsTest.scala
@@ -49,7 +49,7 @@ class InsightsTestE2E extends AnyFunSuite {
index = "products",
userToken = "user-123456",
authenticatedUserToken = Some("user-123456"),
- timestamp = Some(1730678400000L),
+ timestamp = Some(1730937600000L),
objectIDs = Seq("9780545139700", "9780439784542"),
queryID = "43b15df305339e827f0ac0bdc5ebcaa7"
),
@@ -59,7 +59,7 @@ class InsightsTestE2E extends AnyFunSuite {
index = "products",
userToken = "user-123456",
authenticatedUserToken = Some("user-123456"),
- timestamp = Some(1730678400000L),
+ timestamp = Some(1730937600000L),
objectIDs = Seq("9780545139700", "9780439784542")
)
)
diff --git a/tests/output/scala/src/test/scala/algoliasearch/requests/AbtestingTest.scala b/tests/output/scala/src/test/scala/algoliasearch/requests/AbtestingTest.scala
index f14a04c456c..9439d6bcbf2 100644
--- a/tests/output/scala/src/test/scala/algoliasearch/requests/AbtestingTest.scala
+++ b/tests/output/scala/src/test/scala/algoliasearch/requests/AbtestingTest.scala
@@ -562,6 +562,46 @@ class AbtestingTest extends AnyFunSuite {
assert(res.body.isEmpty)
}
+ test("estimate AB Test sample size") {
+ val (client, echo) = testClient()
+ val future = client.estimateABTest(
+ estimateABTestRequest = EstimateABTestRequest(
+ configuration = EstimateConfiguration(
+ emptySearch = Some(
+ EmptySearch(
+ exclude = Some(true)
+ )
+ ),
+ minimumDetectableEffect = MinimumDetectableEffect(
+ size = 0.03,
+ metric = EffectMetric.withName("conversionRate")
+ )
+ ),
+ variants = Seq(
+ AbTestsVariant(
+ index = "AB_TEST_1",
+ trafficPercentage = 50
+ ),
+ AbTestsVariant(
+ index = "AB_TEST_2",
+ trafficPercentage = 50
+ )
+ )
+ )
+ )
+
+ Await.ready(future, Duration.Inf)
+ val res = echo.lastResponse.get
+
+ assert(res.path == "/2/abtests/estimate")
+ assert(res.method == "POST")
+ val expectedBody = parse(
+ """{"configuration":{"emptySearch":{"exclude":true},"minimumDetectableEffect":{"size":0.03,"metric":"conversionRate"}},"variants":[{"index":"AB_TEST_1","trafficPercentage":50},{"index":"AB_TEST_2","trafficPercentage":50}]}"""
+ )
+ val actualBody = parse(res.body.get)
+ assert(actualBody == expectedBody)
+ }
+
test("getABTest") {
val (client, echo) = testClient()
val future = client.getABTest(
diff --git a/tests/output/scala/src/test/scala/algoliasearch/requests/InsightsTest.scala b/tests/output/scala/src/test/scala/algoliasearch/requests/InsightsTest.scala
index 9d52d7bd8fb..ccc91f725f2 100644
--- a/tests/output/scala/src/test/scala/algoliasearch/requests/InsightsTest.scala
+++ b/tests/output/scala/src/test/scala/algoliasearch/requests/InsightsTest.scala
@@ -574,7 +574,7 @@ class InsightsTest extends AnyFunSuite {
index = "products",
userToken = "user-123456",
authenticatedUserToken = Some("user-123456"),
- timestamp = Some(1730678400000L),
+ timestamp = Some(1730937600000L),
objectIDs = Seq("9780545139700", "9780439784542"),
queryID = "43b15df305339e827f0ac0bdc5ebcaa7"
),
@@ -584,7 +584,7 @@ class InsightsTest extends AnyFunSuite {
index = "products",
userToken = "user-123456",
authenticatedUserToken = Some("user-123456"),
- timestamp = Some(1730678400000L),
+ timestamp = Some(1730937600000L),
objectIDs = Seq("9780545139700", "9780439784542")
)
)
@@ -597,7 +597,7 @@ class InsightsTest extends AnyFunSuite {
assert(res.path == "/1/events")
assert(res.method == "POST")
val expectedBody = parse(
- """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730678400000,"objectIDs":["9780545139700","9780439784542"]}]}"""
+ """{"events":[{"eventType":"conversion","eventName":"Product Purchased","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"],"queryID":"43b15df305339e827f0ac0bdc5ebcaa7"},{"eventType":"view","eventName":"Product Detail Page Viewed","index":"products","userToken":"user-123456","authenticatedUserToken":"user-123456","timestamp":1730937600000,"objectIDs":["9780545139700","9780439784542"]}]}"""
)
val actualBody = parse(res.body.get)
assert(actualBody == expectedBody)
diff --git a/tests/output/swift/Tests/e2e/InsightsTests.swift b/tests/output/swift/Tests/e2e/InsightsTests.swift
index 945b6613699..8b4a55ba88c 100644
--- a/tests/output/swift/Tests/e2e/InsightsTests.swift
+++ b/tests/output/swift/Tests/e2e/InsightsTests.swift
@@ -65,7 +65,7 @@ final class InsightsClientRequestsTestsE2E: XCTestCase {
queryID: "43b15df305339e827f0ac0bdc5ebcaa7",
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: Int64(1_730_678_400_000)
+ timestamp: Int64(1_730_937_600_000)
)),
EventsItems.viewedObjectIDs(ViewedObjectIDs(
eventName: "Product Detail Page Viewed",
@@ -74,7 +74,7 @@ final class InsightsClientRequestsTestsE2E: XCTestCase {
objectIDs: ["9780545139700", "9780439784542"],
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: Int64(1_730_678_400_000)
+ timestamp: Int64(1_730_937_600_000)
)),
]))
let responseBody = try XCTUnwrap(response.body)
diff --git a/tests/output/swift/Tests/requests/AbtestingTests.swift b/tests/output/swift/Tests/requests/AbtestingTests.swift
index 91cf53c9571..ec906b027a0 100644
--- a/tests/output/swift/Tests/requests/AbtestingTests.swift
+++ b/tests/output/swift/Tests/requests/AbtestingTests.swift
@@ -759,6 +759,48 @@ final class AbtestingClientRequestsTests: XCTestCase {
XCTAssertNil(echoResponse.queryParameters)
}
+ /// estimate AB Test sample size
+ func testEstimateABTestTest() async throws {
+ let configuration = try AbtestingClientConfiguration(
+ appID: AbtestingClientRequestsTests.APPLICATION_ID,
+ apiKey: AbtestingClientRequestsTests.API_KEY,
+ region: Region.us
+ )
+ let transporter = Transporter(configuration: configuration, requestBuilder: EchoRequestBuilder())
+ let client = AbtestingClient(configuration: configuration, transporter: transporter)
+
+ let response = try await client.estimateABTestWithHTTPInfo(estimateABTestRequest: EstimateABTestRequest(
+ configuration: EstimateConfiguration(
+ emptySearch: EmptySearch(exclude: true),
+ minimumDetectableEffect: MinimumDetectableEffect(
+ size: 0.03,
+ metric: EffectMetric.conversionRate
+ )
+ ),
+ variants: [
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_1", trafficPercentage: 50)),
+ AddABTestsVariant.abTestsVariant(AbTestsVariant(index: "AB_TEST_2", trafficPercentage: 50)),
+ ]
+ ))
+ let responseBodyData = try XCTUnwrap(response.bodyData)
+ let echoResponse = try CodableHelper.jsonDecoder.decode(EchoResponse.self, from: responseBodyData)
+
+ let echoResponseBodyData = try XCTUnwrap(echoResponse.originalBodyData)
+ let echoResponseBodyJSON = try XCTUnwrap(echoResponseBodyData.jsonString)
+
+ let expectedBodyData =
+ "{\"configuration\":{\"emptySearch\":{\"exclude\":true},\"minimumDetectableEffect\":{\"size\":0.03,\"metric\":\"conversionRate\"}},\"variants\":[{\"index\":\"AB_TEST_1\",\"trafficPercentage\":50},{\"index\":\"AB_TEST_2\",\"trafficPercentage\":50}]}"
+ .data(using: .utf8)
+ let expectedBodyJSON = try XCTUnwrap(expectedBodyData?.jsonString)
+
+ XCTAssertEqual(echoResponseBodyJSON, expectedBodyJSON)
+
+ XCTAssertEqual(echoResponse.path, "/2/abtests/estimate")
+ XCTAssertEqual(echoResponse.method, HTTPMethod.post)
+
+ XCTAssertNil(echoResponse.queryParameters)
+ }
+
/// getABTest
func testGetABTestTest() async throws {
let configuration = try AbtestingClientConfiguration(
diff --git a/tests/output/swift/Tests/requests/InsightsTests.swift b/tests/output/swift/Tests/requests/InsightsTests.swift
index 1413f3107ae..b6d714462ea 100644
--- a/tests/output/swift/Tests/requests/InsightsTests.swift
+++ b/tests/output/swift/Tests/requests/InsightsTests.swift
@@ -785,7 +785,7 @@ final class InsightsClientRequestsTests: XCTestCase {
queryID: "43b15df305339e827f0ac0bdc5ebcaa7",
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: Int64(1_730_678_400_000)
+ timestamp: Int64(1_730_937_600_000)
)),
EventsItems.viewedObjectIDs(ViewedObjectIDs(
eventName: "Product Detail Page Viewed",
@@ -794,7 +794,7 @@ final class InsightsClientRequestsTests: XCTestCase {
objectIDs: ["9780545139700", "9780439784542"],
userToken: "user-123456",
authenticatedUserToken: "user-123456",
- timestamp: Int64(1_730_678_400_000)
+ timestamp: Int64(1_730_937_600_000)
)),
]))
let responseBodyData = try XCTUnwrap(response.bodyData)
@@ -804,7 +804,7 @@ final class InsightsClientRequestsTests: XCTestCase {
let echoResponseBodyJSON = try XCTUnwrap(echoResponseBodyData.jsonString)
let expectedBodyData =
- "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730678400000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}"
+ "{\"events\":[{\"eventType\":\"conversion\",\"eventName\":\"Product Purchased\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"],\"queryID\":\"43b15df305339e827f0ac0bdc5ebcaa7\"},{\"eventType\":\"view\",\"eventName\":\"Product Detail Page Viewed\",\"index\":\"products\",\"userToken\":\"user-123456\",\"authenticatedUserToken\":\"user-123456\",\"timestamp\":1730937600000,\"objectIDs\":[\"9780545139700\",\"9780439784542\"]}]}"
.data(using: .utf8)
let expectedBodyJSON = try XCTUnwrap(expectedBodyData?.jsonString)