diff --git a/.github/workflows/ci_v26.0.yml b/.github/workflows/ci_v26.0.yml index 3048581..a60cad5 100644 --- a/.github/workflows/ci_v26.0.yml +++ b/.github/workflows/ci_v26.0.yml @@ -1,11 +1,13 @@ name: CI v26.0 on: - push: - branches: ["main"] pull_request: branches: ["main"] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs # Workflows that would otherwise be triggered using `on: push` or @@ -19,7 +21,9 @@ jobs: # - [actions skip] test: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} runs-on: ubuntu-latest + environment: review env: MIX_ENV: test diff --git a/.github/workflows/ci_v27.0.yml b/.github/workflows/ci_v27.0.yml index 9a2f3db..afd60cc 100644 --- a/.github/workflows/ci_v27.0.yml +++ b/.github/workflows/ci_v27.0.yml @@ -1,11 +1,13 @@ name: CI v27.0 on: - push: - branches: ["main"] pull_request: branches: ["main"] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs # Workflows that would otherwise be triggered using `on: push` or @@ -19,7 +21,9 @@ jobs: # - [actions skip] test: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} runs-on: ubuntu-latest + environment: review env: MIX_ENV: test diff --git a/.github/workflows/ci_v27.1.yml b/.github/workflows/ci_v27.1.yml index 084af47..7a47b32 100644 --- a/.github/workflows/ci_v27.1.yml +++ b/.github/workflows/ci_v27.1.yml @@ -1,11 +1,13 @@ name: CI v27.1 on: - push: - branches: ["main"] pull_request: branches: ["main"] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs # Workflows that would otherwise be triggered using `on: push` or @@ -19,7 +21,9 @@ jobs: # - [actions skip] test: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} runs-on: ubuntu-latest + environment: review env: MIX_ENV: test diff --git a/.github/workflows/ci_v28.0.yml b/.github/workflows/ci_v28.0.yml index e90b490..36f42c7 100644 --- a/.github/workflows/ci_v28.0.yml +++ b/.github/workflows/ci_v28.0.yml @@ -1,11 +1,13 @@ name: CI v28.0 on: - push: - branches: ["main"] pull_request: branches: ["main"] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: # https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs # Workflows that would otherwise be triggered using `on: push` or @@ -19,7 +21,9 @@ jobs: # - [actions skip] test: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} runs-on: ubuntu-latest + environment: review env: MIX_ENV: test @@ -36,7 +40,7 @@ jobs: - typesense: '28.0' otp: '27' elixir: '1.18' - lint: true + lint: false services: typesense: diff --git a/.github/workflows/ci_v29.0.yml b/.github/workflows/ci_v29.0.yml new file mode 100644 index 0000000..d55b9d3 --- /dev/null +++ b/.github/workflows/ci_v29.0.yml @@ -0,0 +1,172 @@ +name: CI v29.0 + +on: + workflow_call: + pull_request: + branches: ["main"] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs + # Workflows that would otherwise be triggered using `on: push` or + # `on: pull_request` won't be triggered if you add any of the + # following strings to the commit message in a push, or the HEAD + # commit of a pull request: + # - [skip ci] + # - [ci skip] + # - [no ci] + # - [skip actions] + # - [actions skip] + + test: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} + runs-on: ubuntu-latest + environment: review + + env: + MIX_ENV: test + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LATEST_TYPESENSE: '29.0' + + strategy: + matrix: + include: + - typesense: '29.0' + otp: '25' + elixir: '1.14' + lint: false + - typesense: '29.0' + otp: '28' + elixir: '1.18' + lint: true + + services: + typesense: + image: typesense/typesense:${{ matrix.typesense }} + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Check for misspellings + uses: codespell-project/actions-codespell@v2 + + - name: Start Typesense + run: | + docker run -id \ + -p 8108:8108 \ + --name typesense \ + -v /tmp/typesense-data:/data \ + -v /tmp/typesense-analytics-data:/analytics-data \ + typesense/typesense:${{ matrix.typesense}} \ + --api-key xyz \ + --data-dir /data \ + --enable-search-analytics=true \ + --analytics-dir=/analytics-data \ + --analytics-flush-interval=60 \ + --analytics-minute-rate-limit=100 \ + --enable-cors + + - name: Wait for Typesense to be healthy + shell: bash + run: | + start_time=$(date +%s) + timeout=30 + counter=0 + until curl -s http://localhost:8108/health | grep -q '"ok":true'; do + if [ $counter -eq $timeout ]; then + echo "Timed out waiting for Typesense to be healthy" + exit 1 + fi + echo "Waiting for Typesense to be healthy..." + sleep 1 + counter=$((counter + 1)) + done + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + echo "Typesense healthcheck elapsed: ${elapsed}s" + + - name: Setup Elixir/OTP + uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.otp}} + elixir-version: ${{matrix.elixir}} + + - name: Cache dependencies/builds + uses: actions/cache@v4 + with: + path: | + deps + _build + key: ${{ runner.os }}-typesense-${{ matrix.typesense}}-${{ matrix.otp}}-${{ matrix.elixir}}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: | + ${{ runner.os }}-typesense-${{ matrix.typesense}}-${{ matrix.otp }}-${{ matrix.elixir }}-mix- + + - name: Install Dependencies + run: | + mix local.rebar --if-missing + mix local.hex --if-missing + mix deps.get + + - name: Find unused dependencies + run: mix deps.unlock --check-unused + if: ${{ matrix.lint }} + + - name: Check retired dependencies + run: mix hex.audit + if: ${{ matrix.lint }} + + - name: Security audit of dependencies + run: mix deps.audit + if: ${{ matrix.lint }} + + - name: Compile project + run: mix compile --all-warnings + + - name: Run static analysis + run: mix credo --all --strict + if: ${{ matrix.lint }} + + - name: Check format files + run: mix format --check-formatted + if: ${{ matrix.lint }} + + - name: Restore PLT cache + id: plt_cache + uses: actions/cache/restore@v4 + with: + key: | + plt-${{ runner.os }}-${{ steps.beam.outputs.otp-version }}-${{ steps.beam.outputs.elixir-version }}-${{ hashFiles('**/mix.lock') }} + restore-keys: | + plt-${{ runner.os }}-${{ steps.beam.outputs.otp-version }}-${{ steps.beam.outputs.elixir-version }}- + path: | + priv/plts + if: ${{ matrix.lint }} + + - name: Create PLTs + if: ${{ steps.plt_cache.outputs.cache-hit != 'true' && matrix.lint }} + run: mix dialyzer --plt + + - name: Save PLT cache + id: plt_cache_save + uses: actions/cache/save@v4 + if: ${{ steps.plt_cache.outputs.cache-hit != 'true' && matrix.lint }} + with: + key: | + plt-${{ runner.os }}-${{ steps.beam.outputs.otp-version }}-${{ steps.beam.outputs.elixir-version }}-${{ hashFiles('**/mix.lock') }} + path: | + priv/plts + + - name: Dialyzer + run: mix dialyzer --format github --format dialyxir + if: ${{ matrix.lint }} + + - name: Run tests + run: mix test --only ${{ matrix.typesense }}:true --trace + + - name: Post test coverage to Coveralls + run: mix coveralls.github + if: ${{ matrix.lint && github.event_name == 'push' && github.ref == 'refs/heads/main' }} diff --git a/.github/workflows/llm.yml b/.github/workflows/llm.yml new file mode 100644 index 0000000..98307f6 --- /dev/null +++ b/.github/workflows/llm.yml @@ -0,0 +1,95 @@ +name: LLM +on: + pull_request: + branches: ["main"] + +# concurrency: +# group: ${{ github.workflow }}-${{ github.ref }} +# cancel-in-progress: true + +jobs: + ci_workflow: + uses: ./.github/workflows/ci_v29.0.yml + secrets: inherit + + llm: + if: ${{ (github.event_name == 'push' || github.event_name == 'pull_request') && github.repository == 'jaeyson/open_api_typesense' }} + runs-on: ubuntu-latest + environment: review + needs: [ci_workflow] + + env: + MIX_ENV: test + + strategy: + matrix: + include: + - typesense: '29.0' + otp: '28' + elixir: '1.18' + + services: + typesense: + image: typesense/typesense:${{ matrix.typesense }} + + steps: + - name: Start Typesense + run: | + docker run -id \ + -p 8108:8108 \ + --name typesense \ + -v /tmp/typesense-data:/data \ + -v /tmp/typesense-analytics-data:/analytics-data \ + typesense/typesense:${{ matrix.typesense}} \ + --api-key xyz \ + --data-dir /data \ + --enable-search-analytics=true \ + --analytics-dir=/analytics-data \ + --analytics-flush-interval=60 \ + --analytics-minute-rate-limit=100 \ + --enable-cors + + - name: Wait for Typesense to be healthy + shell: bash + run: | + start_time=$(date +%s) + timeout=30 + counter=0 + until curl -s http://localhost:8108/health | grep -q '"ok":true'; do + if [ $counter -eq $timeout ]; then + echo "Timed out waiting for Typesense to be healthy" + exit 1 + fi + echo "Waiting for Typesense to be healthy..." + sleep 1 + counter=$((counter + 1)) + done + end_time=$(date +%s) + elapsed=$((end_time - start_time)) + echo "Typesense healthcheck elapsed: ${elapsed}s" + + - name: Checkout repo + uses: actions/checkout@v5 + + - name: Setup Elixir/OTP + uses: erlef/setup-beam@v1 + with: + otp-version: ${{matrix.otp}} + elixir-version: ${{matrix.elixir}} + + - name: Cache typesense-data + uses: actions/cache@v4 + with: + path: | + typesense-data + key: ${{ runner.os }}-typesense-data + restore-keys: | + ${{ runner.os }}-typesense-data + + - name: Test natural language search + run: mix test --only nls:true --trace + if: ${{ github.event_name == 'pull_request' && github.ref == 'refs/heads/main' }} + + - name: Post test coverage to Coveralls + run: mix coveralls.github + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} diff --git a/.gitignore b/.gitignore index c4eb9a7..f4d5269 100644 --- a/.gitignore +++ b/.gitignore @@ -36,5 +36,7 @@ open_api_typesense-*.tar .elixir_ls **.DS_Store +*.env + /priv/plts/*.plt /priv/plts/*.plt.hash diff --git a/CHANGELOG.md b/CHANGELOG.md index ea501f1..75bf8e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## major.minor.patch (yyyy.mm.dd) +## 1.1.1 ??? + +### Added + +* `NlSearchModels` operation +* `Analytics.flush_analytics/1` +* `Analytics.get_analytics_status/1` +* `Analytics.get_analytics_events/1` + +### Chore + +* update `priv/open_api.yml` to https://github.com/typesense/typesense-api-spec/commit/eac4e46bc934dd1f621406602c2c46184961788f +* Changed `DropTokensMode` schema from string to object. + +### Removed + +* `Operations.config/2`. Use `Operations.toggle_slow_request_log/2` + ## 1.0.4 (2025.06.18) ### Fixed diff --git a/README.md b/README.md index cdf5ec8..fe4fc14 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Restful client for Typesense with adherence to Open API spec 3 (formerly Swagger [![Codacy Badge](https://app.codacy.com/project/badge/Grade/965dd3f8866d49c3b3e82edd0f6270cb)](https://app.codacy.com/gh/jaeyson/open_api_typesense/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![codescenene Average Code Health](https://codescene.io/projects/63240/status-badges/average-code-health)](https://codescene.io/projects/63240) +[![CI v29.0](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v29.0.yml/badge.svg)](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v29.0.yml) [![CI v28.0](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v28.0.yml/badge.svg)](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v28.0.yml) [![CI v27.1](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v27.1.yml/badge.svg)](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v27.1.yml) [![CI v27.0](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v27.0.yml/badge.svg)](https://github.com/jaeyson/open_api_typesense/actions/workflows/ci_v27.0.yml) @@ -32,6 +33,9 @@ Collections.get_collections(conn: conn) # another way (v1) opts = [limit: 1, conn: conn] Collections.get_collections(opts) + +# or (v1) +Collections.get_collections(limit: 1, conn: conn) ``` ## Installation @@ -41,7 +45,7 @@ by adding `open_api_typesense` to your list of dependencies in `mix.exs`: ```elixir def deps do [ - {:open_api_typesense, "~> 1.0"} + {:open_api_typesense, "~> 1.1"} # Or from GitHub repository, if you want the latest greatest from main branch {:open_api_typesense, git: "https://github.com/jaeyson/open_api_typesense.git"} diff --git a/dev.env.example b/dev.env.example new file mode 100644 index 0000000..833376a --- /dev/null +++ b/dev.env.example @@ -0,0 +1 @@ +export GEMINI_API_KEY=google_xyz \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d672867..b922d20 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: typesense: - image: docker.io/typesense/typesense:28.0 + image: docker.io/typesense/typesense:29.0 container_name: typesense restart: on-failure ports: @@ -18,7 +18,7 @@ services: --analytics-minute-rate-limit=100 --enable-cors typesense_dashboard: - image: ghcr.io/bfritscher/typesense-dashboard:1.9.3 + image: ghcr.io/bfritscher/typesense-dashboard:2.1.0 container_name: typesense_dashboard restart: on-failure ports: diff --git a/guides/custom_http_client.md b/guides/custom_http_client.md index 078d26f..3342aa9 100644 --- a/guides/custom_http_client.md +++ b/guides/custom_http_client.md @@ -16,7 +16,7 @@ config :open_api_typesense, ## [`:httpc`](https://www.erlang.org/doc/apps/inets/httpc.html) ```elixir -defmodule CustomClient do +defmodule MyApp.CustomClient do @behaviour OpenApiTypesense.Client @impl OpenApiTypesense.Client diff --git a/lib/open_api_typesense/client.ex b/lib/open_api_typesense/client.ex index e203e1b..b0f78b3 100644 --- a/lib/open_api_typesense/client.ex +++ b/lib/open_api_typesense/client.ex @@ -156,7 +156,7 @@ defmodule OpenApiTypesense.Client do {:ok, []} end - defp parse_body(_code, [{mod, _t}], body) when is_binary(body) do + defp parse_body(_code, [{mod, _t}], body) do {:ok, Poison.decode!(body, as: [mod.__struct__()])} end diff --git a/lib/open_api_typesense/operations/analytics.ex b/lib/open_api_typesense/operations/analytics.ex index 88efd0a..688ff54 100644 --- a/lib/open_api_typesense/operations/analytics.ex +++ b/lib/open_api_typesense/operations/analytics.ex @@ -10,7 +10,7 @@ defmodule OpenApiTypesense.Analytics do @doc """ Create an analytics event - Sending events for analytics e.g rank search results based on popularity. + Submit a single analytics event. The event must correspond to an existing analytics rule by name. """ @doc since: "0.4.0" @spec create_analytics_event( @@ -28,9 +28,9 @@ defmodule OpenApiTypesense.Analytics do url: "/analytics/events", body: body, method: :post, - request: [{"application/json", {OpenApiTypesense.AnalyticsEventCreateSchema, :t}}], + request: [{"application/json", {OpenApiTypesense.AnalyticsEvent, :t}}], response: [ - {201, {OpenApiTypesense.AnalyticsEventCreateResponse, :t}}, + {200, {OpenApiTypesense.AnalyticsEventCreateResponse, :t}}, {400, {OpenApiTypesense.ApiResponse, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}} ], @@ -39,13 +39,17 @@ defmodule OpenApiTypesense.Analytics do end @doc """ - Creates an analytics rule + Create analytics rule(s) - When an analytics rule is created, we give it a name and describe the type, the source collections and the destination collection. + Create one or more analytics rules. You can send a single rule object or an array of rule objects. """ @doc since: "0.4.0" - @spec create_analytics_rule(body :: OpenApiTypesense.AnalyticsRuleSchema.t(), opts :: keyword) :: - {:ok, OpenApiTypesense.AnalyticsRuleSchema.t()} + @spec create_analytics_rule( + body :: + OpenApiTypesense.AnalyticsRuleCreate.t() | [OpenApiTypesense.AnalyticsRuleCreate.t()], + opts :: keyword + ) :: + {:ok, OpenApiTypesense.AnalyticsRule.t() | [map | OpenApiTypesense.AnalyticsRule.t()]} | {:error, OpenApiTypesense.ApiResponse.t()} def create_analytics_rule(body, opts \\ []) do client = opts[:client] || @default_client @@ -56,9 +60,21 @@ defmodule OpenApiTypesense.Analytics do url: "/analytics/rules", body: body, method: :post, - request: [{"application/json", {OpenApiTypesense.AnalyticsRuleSchema, :t}}], + request: [ + {"application/json", + {:union, + [ + {OpenApiTypesense.AnalyticsRuleCreate, :t}, + [{OpenApiTypesense.AnalyticsRuleCreate, :t}] + ]}} + ], response: [ - {201, {OpenApiTypesense.AnalyticsRuleSchema, :t}}, + {200, + {:union, + [ + {OpenApiTypesense.AnalyticsRule, :t}, + [union: [:map, {OpenApiTypesense.AnalyticsRule, :t}]] + ]}}, {400, {OpenApiTypesense.ApiResponse, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}}, {404, {OpenApiTypesense.ApiResponse, :t}} @@ -74,8 +90,7 @@ defmodule OpenApiTypesense.Analytics do """ @doc since: "0.4.0" @spec delete_analytics_rule(rule_name :: String.t(), opts :: keyword) :: - {:ok, OpenApiTypesense.AnalyticsRuleDeleteResponse.t()} - | {:error, OpenApiTypesense.ApiResponse.t()} + {:ok, OpenApiTypesense.AnalyticsRule.t()} | {:error, OpenApiTypesense.ApiResponse.t()} def delete_analytics_rule(rule_name, opts \\ []) do client = opts[:client] || @default_client @@ -85,7 +100,7 @@ defmodule OpenApiTypesense.Analytics do url: "/analytics/rules/#{rule_name}", method: :delete, response: [ - {200, {OpenApiTypesense.AnalyticsRuleDeleteResponse, :t}}, + {200, {OpenApiTypesense.AnalyticsRule, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}}, {404, {OpenApiTypesense.ApiResponse, :t}} ], @@ -93,6 +108,82 @@ defmodule OpenApiTypesense.Analytics do }) end + @doc """ + Flush in-memory analytics to disk + + Triggers a flush of analytics data to persistent storage. + """ + @doc since: "1.1.0" + @spec flush_analytics(opts :: keyword) :: + {:ok, OpenApiTypesense.AnalyticsEventCreateResponse.t()} | :error + def flush_analytics(opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [], + call: {OpenApiTypesense.Analytics, :flush_analytics}, + url: "/analytics/flush", + method: :post, + response: [{200, {OpenApiTypesense.AnalyticsEventCreateResponse, :t}}], + opts: opts + }) + end + + @doc """ + Retrieve analytics events + + Retrieve the most recent events for a user and rule. + + ## Options + + * `user_id` + * `name`: Analytics rule name + * `n`: Number of events to return (max 1000) + + """ + @doc since: "1.1.0" + @spec get_analytics_events(opts :: keyword) :: + {:ok, OpenApiTypesense.AnalyticsEventsResponse.t()} + | {:error, OpenApiTypesense.ApiResponse.t()} + def get_analytics_events(opts \\ []) do + client = opts[:client] || @default_client + query = Keyword.take(opts, [:n, :name, :user_id]) + + client.request(%{ + args: [], + call: {OpenApiTypesense.Analytics, :get_analytics_events}, + url: "/analytics/events", + method: :get, + query: query, + response: [ + {200, {OpenApiTypesense.AnalyticsEventsResponse, :t}}, + {400, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + + @doc """ + Get analytics subsystem status + + Returns sizes of internal analytics buffers and queues. + """ + @doc since: "1.1.0" + @spec get_analytics_status(opts :: keyword) :: + {:ok, OpenApiTypesense.AnalyticsStatus.t()} | :error + def get_analytics_status(opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [], + call: {OpenApiTypesense.Analytics, :get_analytics_status}, + url: "/analytics/status", + method: :get, + response: [{200, {OpenApiTypesense.AnalyticsStatus, :t}}], + opts: opts + }) + end + @doc """ Retrieves an analytics rule @@ -100,8 +191,7 @@ defmodule OpenApiTypesense.Analytics do """ @doc since: "0.4.0" @spec retrieve_analytics_rule(rule_name :: String.t(), opts :: keyword) :: - {:ok, OpenApiTypesense.AnalyticsRuleSchema.t()} - | {:error, OpenApiTypesense.ApiResponse.t()} + {:ok, OpenApiTypesense.AnalyticsRule.t()} | {:error, OpenApiTypesense.ApiResponse.t()} def retrieve_analytics_rule(rule_name, opts \\ []) do client = opts[:client] || @default_client @@ -111,7 +201,7 @@ defmodule OpenApiTypesense.Analytics do url: "/analytics/rules/#{rule_name}", method: :get, response: [ - {200, {OpenApiTypesense.AnalyticsRuleSchema, :t}}, + {200, {OpenApiTypesense.AnalyticsRule, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}}, {404, {OpenApiTypesense.ApiResponse, :t}} ], @@ -120,24 +210,30 @@ defmodule OpenApiTypesense.Analytics do end @doc """ - Retrieves all analytics rules + Retrieve analytics rules + + Retrieve all analytics rules. Use the optional rule_tag filter to narrow down results. + + ## Options + + * `rule_tag`: Filter rules by rule_tag - Retrieve the details of all analytics rules """ @doc since: "0.4.0" @spec retrieve_analytics_rules(opts :: keyword) :: - {:ok, OpenApiTypesense.AnalyticsRulesRetrieveSchema.t()} - | {:error, OpenApiTypesense.ApiResponse.t()} + {:ok, [OpenApiTypesense.AnalyticsRule.t()]} | {:error, OpenApiTypesense.ApiResponse.t()} def retrieve_analytics_rules(opts \\ []) do client = opts[:client] || @default_client + query = Keyword.take(opts, [:rule_tag]) client.request(%{ args: [], call: {OpenApiTypesense.Analytics, :retrieve_analytics_rules}, url: "/analytics/rules", method: :get, + query: query, response: [ - {200, {OpenApiTypesense.AnalyticsRulesRetrieveSchema, :t}}, + {200, [{OpenApiTypesense.AnalyticsRule, :t}]}, {401, {OpenApiTypesense.ApiResponse, :t}} ], opts: opts @@ -152,11 +248,10 @@ defmodule OpenApiTypesense.Analytics do @doc since: "0.4.0" @spec upsert_analytics_rule( rule_name :: String.t(), - body :: OpenApiTypesense.AnalyticsRuleUpsertSchema.t(), + body :: OpenApiTypesense.AnalyticsRuleUpdate.t(), opts :: keyword ) :: - {:ok, OpenApiTypesense.AnalyticsRuleSchema.t()} - | {:error, OpenApiTypesense.ApiResponse.t()} + {:ok, OpenApiTypesense.AnalyticsRule.t()} | {:error, OpenApiTypesense.ApiResponse.t()} def upsert_analytics_rule(rule_name, body, opts \\ []) do client = opts[:client] || @default_client @@ -166,9 +261,9 @@ defmodule OpenApiTypesense.Analytics do url: "/analytics/rules/#{rule_name}", body: body, method: :put, - request: [{"application/json", {OpenApiTypesense.AnalyticsRuleUpsertSchema, :t}}], + request: [{"application/json", {OpenApiTypesense.AnalyticsRuleUpdate, :t}}], response: [ - {200, {OpenApiTypesense.AnalyticsRuleSchema, :t}}, + {200, {OpenApiTypesense.AnalyticsRule, :t}}, {400, {OpenApiTypesense.ApiResponse, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}} ], diff --git a/lib/open_api_typesense/operations/conversations.ex b/lib/open_api_typesense/operations/conversations.ex index 2c02883..0d93c52 100644 --- a/lib/open_api_typesense/operations/conversations.ex +++ b/lib/open_api_typesense/operations/conversations.ex @@ -8,8 +8,6 @@ defmodule OpenApiTypesense.Conversations do @default_client OpenApiTypesense.Client @doc """ - post `/conversations/models` - Create a Conversation Model """ @doc since: "0.4.0" @@ -39,8 +37,6 @@ defmodule OpenApiTypesense.Conversations do end @doc """ - Delete a conversation model - Delete a conversation model """ @doc since: "0.4.0" @@ -65,8 +61,6 @@ defmodule OpenApiTypesense.Conversations do end @doc """ - List all conversation models - Retrieve all conversation models """ @doc since: "0.4.0" @@ -90,8 +84,6 @@ defmodule OpenApiTypesense.Conversations do end @doc """ - Retrieve a conversation model - Retrieve a conversation model """ @doc since: "0.4.0" @@ -116,8 +108,6 @@ defmodule OpenApiTypesense.Conversations do end @doc """ - Update a conversation model - Update a conversation model """ @doc since: "0.4.0" diff --git a/lib/open_api_typesense/operations/curation.ex b/lib/open_api_typesense/operations/curation.ex index d19768d..3b415c2 100644 --- a/lib/open_api_typesense/operations/curation.ex +++ b/lib/open_api_typesense/operations/curation.ex @@ -92,6 +92,7 @@ defmodule OpenApiTypesense.Curation do request: [{"application/json", {OpenApiTypesense.SearchOverrideSchema, :t}}], response: [ {200, {OpenApiTypesense.SearchOverride, :t}}, + {400, {OpenApiTypesense.ApiResponse, :t}}, {401, {OpenApiTypesense.ApiResponse, :t}}, {404, {OpenApiTypesense.ApiResponse, :t}} ], diff --git a/lib/open_api_typesense/operations/nl_search_models.ex b/lib/open_api_typesense/operations/nl_search_models.ex new file mode 100644 index 0000000..98cbc96 --- /dev/null +++ b/lib/open_api_typesense/operations/nl_search_models.ex @@ -0,0 +1,151 @@ +defmodule OpenApiTypesense.NlSearchModels do + @moduledoc since: "1.1.0" + + @moduledoc """ + Provides API endpoints related to nl search models + """ + + @default_client OpenApiTypesense.Client + + @doc """ + Create a NL search model + + Create a new NL search model. + """ + @doc since: "1.1.0" + @spec create_nl_search_model( + body :: OpenApiTypesense.NLSearchModelCreateSchema.t(), + opts :: keyword + ) :: + {:ok, OpenApiTypesense.NLSearchModelSchema.t()} + | {:error, OpenApiTypesense.ApiResponse.t()} + def create_nl_search_model(body, opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [body: body], + call: {OpenApiTypesense.NlSearchModels, :create_nl_search_model}, + url: "/nl_search_models", + body: body, + method: :post, + request: [{"application/json", {OpenApiTypesense.NLSearchModelCreateSchema, :t}}], + response: [ + {201, {OpenApiTypesense.NLSearchModelSchema, :t}}, + {400, {OpenApiTypesense.ApiResponse, :t}}, + {401, {OpenApiTypesense.ApiResponse, :t}}, + {409, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + + @doc """ + Delete a NL search model + + Delete a specific NL search model by its ID. + """ + @doc since: "1.1.0" + @spec delete_nl_search_model(model_id :: String.t(), opts :: keyword) :: + {:ok, OpenApiTypesense.NLSearchModelDeleteSchema.t()} + | {:error, OpenApiTypesense.ApiResponse.t()} + def delete_nl_search_model(model_id, opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [model_id: model_id], + call: {OpenApiTypesense.NlSearchModels, :delete_nl_search_model}, + url: "/nl_search_models/#{model_id}", + method: :delete, + response: [ + {200, {OpenApiTypesense.NLSearchModelDeleteSchema, :t}}, + {401, {OpenApiTypesense.ApiResponse, :t}}, + {404, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + + @doc """ + List all NL search models + + Retrieve all NL search models. + """ + @doc since: "1.1.0" + @spec retrieve_all_nl_search_models(opts :: keyword) :: + {:ok, [OpenApiTypesense.NLSearchModelSchema.t()]} + | {:error, OpenApiTypesense.ApiResponse.t()} + def retrieve_all_nl_search_models(opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [], + call: {OpenApiTypesense.NlSearchModels, :retrieve_all_nl_search_models}, + url: "/nl_search_models", + method: :get, + response: [ + {200, [{OpenApiTypesense.NLSearchModelSchema, :t}]}, + {401, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + + @doc """ + Retrieve a NL search model + + Retrieve a specific NL search model by its ID. + """ + @doc since: "1.1.0" + @spec retrieve_nl_search_model(model_id :: String.t(), opts :: keyword) :: + {:ok, OpenApiTypesense.NLSearchModelSchema.t()} + | {:error, OpenApiTypesense.ApiResponse.t()} + def retrieve_nl_search_model(model_id, opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [model_id: model_id], + call: {OpenApiTypesense.NlSearchModels, :retrieve_nl_search_model}, + url: "/nl_search_models/#{model_id}", + method: :get, + response: [ + {200, {OpenApiTypesense.NLSearchModelSchema, :t}}, + {401, {OpenApiTypesense.ApiResponse, :t}}, + {404, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + + @doc """ + Update a NL search model + + Update an existing NL search model. + """ + @doc since: "1.1.0" + @spec update_nl_search_model( + model_id :: String.t(), + body :: OpenApiTypesense.NLSearchModelCreateSchema.t(), + opts :: keyword + ) :: + {:ok, OpenApiTypesense.NLSearchModelSchema.t()} + | {:error, OpenApiTypesense.ApiResponse.t()} + def update_nl_search_model(model_id, body, opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [model_id: model_id, body: body], + call: {OpenApiTypesense.NlSearchModels, :update_nl_search_model}, + url: "/nl_search_models/#{model_id}", + body: body, + method: :put, + request: [{"application/json", {OpenApiTypesense.NLSearchModelCreateSchema, :t}}], + response: [ + {200, {OpenApiTypesense.NLSearchModelSchema, :t}}, + {400, {OpenApiTypesense.ApiResponse, :t}}, + {401, {OpenApiTypesense.ApiResponse, :t}}, + {404, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end +end diff --git a/lib/open_api_typesense/operations/operations.ex b/lib/open_api_typesense/operations/operations.ex index 1f97cb2..c856b22 100644 --- a/lib/open_api_typesense/operations/operations.ex +++ b/lib/open_api_typesense/operations/operations.ex @@ -8,9 +8,9 @@ defmodule OpenApiTypesense.Operations do @default_client OpenApiTypesense.Client @doc """ - Clears the cache + Clear the cached responses of search requests in the LRU cache. - Responses of search requests that are sent with use_cache parameter are cached in a LRU cache. Clears cache completely. + Clear the cached responses of search requests that are sent with `use_cache` parameter in the LRU cache. """ @doc since: "0.4.2" @spec clear_cache(opts :: keyword) :: @@ -32,19 +32,19 @@ defmodule OpenApiTypesense.Operations do end @doc """ - Compaction of the underlying RocksDB database + Compacting the on-disk database Typesense uses RocksDB to store your documents on the disk. If you do frequent writes or updates, you could benefit from running a compaction of the underlying RocksDB database. This could reduce the size of the database and decrease read latency. While the database will not block during this operation, we recommend running it during off-peak hours. """ @doc since: "0.4.2" - @spec compact(opts :: keyword) :: + @spec compact_db(opts :: keyword) :: {:ok, OpenApiTypesense.SuccessStatus.t()} | {:error, OpenApiTypesense.ApiResponse.t()} - def compact(opts \\ []) do + def compact_db(opts \\ []) do client = opts[:client] || @default_client client.request(%{ args: [], - call: {OpenApiTypesense.Operations, :compact}, + call: {OpenApiTypesense.Operations, :compact_db}, url: "/operations/db/compact", method: :post, response: [ @@ -55,33 +55,6 @@ defmodule OpenApiTypesense.Operations do }) end - @doc """ - Enable logging of requests that take over a defined threshold of time. - - Slow requests are logged to the primary log file, with the prefix SLOW REQUEST. Default is -1 which disables slow request logging. - """ - @doc since: "0.4.2" - @spec config(body :: OpenApiTypesense.ConfigSchema.t(), opts :: keyword) :: - {:ok, OpenApiTypesense.SuccessStatus.t()} | {:error, OpenApiTypesense.ApiResponse.t()} - def config body, opts \\ [] do - client = opts[:client] || @default_client - - client.request(%{ - args: [body: body], - call: {OpenApiTypesense.Operations, :config}, - url: "/config", - body: body, - method: :post, - request: [{"application/json", {OpenApiTypesense.ConfigSchema, :t}}], - response: [ - {201, {OpenApiTypesense.SuccessStatus, :t}}, - {400, {OpenApiTypesense.ApiResponse, :t}}, - {401, {OpenApiTypesense.ApiResponse, :t}} - ], - opts: opts - }) - end - @doc """ Get the status of in-progress schema change operations @@ -186,6 +159,42 @@ defmodule OpenApiTypesense.Operations do }) end + @doc """ + Toggle Slow Request Log + + Enable logging of requests that take over a defined threshold of time. Default is `-1` which disables slow request logging. Slow requests are logged to the primary log file, with the prefix SLOW REQUEST. + + ## Required body + + * `log-slow-requests-time-ms`: Defaults to `-1` + + + ## Example + iex> body = %{"log-slow-requests-time-ms" => 2_000} + iex> OpenApiTypesense.Operations.toggle_slow_request_log(body) + """ + @doc since: "1.1.0" + @spec toggle_slow_request_log(body :: map, opts :: keyword) :: + {:ok, OpenApiTypesense.SuccessStatus.t()} | {:error, OpenApiTypesense.ApiResponse.t()} + def toggle_slow_request_log(body, opts \\ []) do + client = opts[:client] || @default_client + + client.request(%{ + args: [body: body], + call: {OpenApiTypesense.Operations, :toggle_slow_request_log}, + url: "/config", + body: body, + method: :post, + request: [{"application/json", :map}], + response: [ + {201, {OpenApiTypesense.SuccessStatus, :t}}, + {400, {OpenApiTypesense.ApiResponse, :t}}, + {401, {OpenApiTypesense.ApiResponse, :t}} + ], + opts: opts + }) + end + @doc """ Triggers a follower node to initiate the raft voting process, which triggers leader re-election. diff --git a/lib/open_api_typesense/schemas/analytics_event.ex b/lib/open_api_typesense/schemas/analytics_event.ex new file mode 100644 index 0000000..5ff570a --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_event.ex @@ -0,0 +1,26 @@ +defmodule OpenApiTypesense.AnalyticsEvent do + @moduledoc """ + Provides struct and type for a AnalyticsEvent + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + data: OpenApiTypesense.AnalyticsEventData.t(), + event_type: String.t(), + name: String.t() + } + + defstruct [:data, :event_type, :name] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + data: {OpenApiTypesense.AnalyticsEventData, :t}, + event_type: {:string, :generic}, + name: {:string, :generic} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_event_data.ex b/lib/open_api_typesense/schemas/analytics_event_data.ex new file mode 100644 index 0000000..5d93959 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_event_data.ex @@ -0,0 +1,30 @@ +defmodule OpenApiTypesense.AnalyticsEventData do + @moduledoc """ + Provides struct and type for a AnalyticsEventData + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + analytics_tag: String.t(), + doc_id: String.t(), + doc_ids: [String.t()], + q: String.t(), + user_id: String.t() + } + + defstruct [:analytics_tag, :doc_id, :doc_ids, :q, :user_id] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + analytics_tag: {:string, :generic}, + doc_id: {:string, :generic}, + doc_ids: [string: :generic], + q: {:string, :generic}, + user_id: {:string, :generic} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_events_response.ex b/lib/open_api_typesense/schemas/analytics_events_response.ex new file mode 100644 index 0000000..a39a442 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_events_response.ex @@ -0,0 +1,54 @@ +defmodule OpenApiTypesense.AnalyticsEventsResponse do + @moduledoc """ + Provides struct and type for a AnalyticsEventsResponse + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{events: [OpenApiTypesense.AnalyticsEventsResponseEvents.t()]} + + defstruct [:events] + + defimpl(Poison.Decoder, for: OpenApiTypesense.AnalyticsEventsResponse) do + def decode(value, %{as: struct}) do + mod = + case struct do + [m] -> m + m -> m + end + + filtered_type = + mod.__struct__.__fields__() + |> Enum.filter(fn {_field, v} -> + case v do + [{mod, :t}] when is_atom(mod) -> true + _ -> false + end + end) + + case filtered_type do + [{_key, [{module, :t}]} | _rest] = list when is_list(list) and is_atom(module) -> + Enum.reduce(list, value, fn {key, [{mod, :t}]}, acc -> + Map.update!(acc, key, fn data -> + body = OpenApiTypesense.Converter.to_atom_keys(data || [], safe: false) + + case body do + [] -> [] + _ -> Enum.map(body, &struct(mod, &1)) + end + end) + end) + + [] -> + value + end + end + end + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [events: [{OpenApiTypesense.AnalyticsEventsResponseEvents, :t}]] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_events_response_events.ex b/lib/open_api_typesense/schemas/analytics_events_response_events.ex new file mode 100644 index 0000000..c1c29cb --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_events_response_events.ex @@ -0,0 +1,36 @@ +defmodule OpenApiTypesense.AnalyticsEventsResponseEvents do + @moduledoc """ + Provides struct and type for a AnalyticsEventsResponseEvents + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + collection: String.t(), + doc_id: String.t(), + doc_ids: [String.t()], + event_type: String.t(), + name: String.t(), + query: String.t(), + timestamp: integer, + user_id: String.t() + } + + defstruct [:collection, :doc_id, :doc_ids, :event_type, :name, :query, :timestamp, :user_id] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + collection: {:string, :generic}, + doc_id: {:string, :generic}, + doc_ids: [string: :generic], + event_type: {:string, :generic}, + name: {:string, :generic}, + query: {:string, :generic}, + timestamp: :integer, + user_id: {:string, :generic} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_rule.ex b/lib/open_api_typesense/schemas/analytics_rule.ex new file mode 100644 index 0000000..293f7c2 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_rule.ex @@ -0,0 +1,32 @@ +defmodule OpenApiTypesense.AnalyticsRule do + @moduledoc """ + Provides struct and type for a AnalyticsRule + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + collection: String.t(), + event_type: String.t(), + name: String.t(), + params: map, + rule_tag: String.t(), + type: String.t() + } + + defstruct [:collection, :event_type, :name, :params, :rule_tag, :type] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + collection: {:string, :generic}, + event_type: {:string, :generic}, + name: {:string, :generic}, + params: :map, + rule_tag: {:string, :generic}, + type: {:enum, ["popular_queries", "nohits_queries", "counter", "log"]} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_rule_create.ex b/lib/open_api_typesense/schemas/analytics_rule_create.ex new file mode 100644 index 0000000..a174792 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_rule_create.ex @@ -0,0 +1,32 @@ +defmodule OpenApiTypesense.AnalyticsRuleCreate do + @moduledoc """ + Provides struct and type for a AnalyticsRuleCreate + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + collection: String.t(), + event_type: String.t(), + name: String.t(), + params: map, + rule_tag: String.t(), + type: String.t() + } + + defstruct [:collection, :event_type, :name, :params, :rule_tag, :type] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + collection: {:string, :generic}, + event_type: {:string, :generic}, + name: {:string, :generic}, + params: :map, + rule_tag: {:string, :generic}, + type: {:enum, ["popular_queries", "nohits_queries", "counter", "log"]} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_rule_update.ex b/lib/open_api_typesense/schemas/analytics_rule_update.ex new file mode 100644 index 0000000..2dd0e41 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_rule_update.ex @@ -0,0 +1,26 @@ +defmodule OpenApiTypesense.AnalyticsRuleUpdate do + @moduledoc """ + Provides struct and type for a AnalyticsRuleUpdate + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + name: String.t(), + params: OpenApiTypesense.AnalyticsRuleUpdateParams.t(), + rule_tag: String.t() + } + + defstruct [:name, :params, :rule_tag] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + name: {:string, :generic}, + params: {OpenApiTypesense.AnalyticsRuleUpdateParams, :t}, + rule_tag: {:string, :generic} + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_rule_update_params.ex b/lib/open_api_typesense/schemas/analytics_rule_update_params.ex new file mode 100644 index 0000000..034e324 --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_rule_update_params.ex @@ -0,0 +1,42 @@ +defmodule OpenApiTypesense.AnalyticsRuleUpdateParams do + @moduledoc """ + Provides struct and type for a AnalyticsRuleUpdateParams + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + capture_search_requests: boolean, + counter_field: String.t(), + destination_collection: String.t(), + expand_query: boolean, + limit: integer, + meta_fields: [String.t()], + weight: integer + } + + defstruct [ + :capture_search_requests, + :counter_field, + :destination_collection, + :expand_query, + :limit, + :meta_fields, + :weight + ] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + capture_search_requests: :boolean, + counter_field: {:string, :generic}, + destination_collection: {:string, :generic}, + expand_query: :boolean, + limit: :integer, + meta_fields: [string: :generic], + weight: :integer + ] + end +end diff --git a/lib/open_api_typesense/schemas/analytics_status.ex b/lib/open_api_typesense/schemas/analytics_status.ex new file mode 100644 index 0000000..12a0f6b --- /dev/null +++ b/lib/open_api_typesense/schemas/analytics_status.ex @@ -0,0 +1,42 @@ +defmodule OpenApiTypesense.AnalyticsStatus do + @moduledoc """ + Provides struct and type for a AnalyticsStatus + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + doc_counter_events: integer, + doc_log_events: integer, + log_prefix_queries: integer, + nohits_prefix_queries: integer, + popular_prefix_queries: integer, + query_counter_events: integer, + query_log_events: integer + } + + defstruct [ + :doc_counter_events, + :doc_log_events, + :log_prefix_queries, + :nohits_prefix_queries, + :popular_prefix_queries, + :query_counter_events, + :query_log_events + ] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + doc_counter_events: :integer, + doc_log_events: :integer, + log_prefix_queries: :integer, + nohits_prefix_queries: :integer, + popular_prefix_queries: :integer, + query_counter_events: :integer, + query_log_events: :integer + ] + end +end diff --git a/lib/open_api_typesense/schemas/collection_response.ex b/lib/open_api_typesense/schemas/collection_response.ex index 8716575..e7f1592 100644 --- a/lib/open_api_typesense/schemas/collection_response.ex +++ b/lib/open_api_typesense/schemas/collection_response.ex @@ -9,9 +9,11 @@ defmodule OpenApiTypesense.CollectionResponse do default_sorting_field: String.t(), enable_nested_fields: boolean, fields: [OpenApiTypesense.Field.t()], + metadata: map, name: String.t(), num_documents: integer, symbols_to_index: [String.t()], + synonym_sets: [String.t()], token_separators: [String.t()], voice_query_model: OpenApiTypesense.VoiceQueryModelCollectionConfig.t() } @@ -19,8 +21,10 @@ defmodule OpenApiTypesense.CollectionResponse do defstruct [ :created_at, :fields, + :metadata, :name, :num_documents, + :synonym_sets, default_sorting_field: "", enable_nested_fields: false, symbols_to_index: [], @@ -74,9 +78,11 @@ defmodule OpenApiTypesense.CollectionResponse do default_sorting_field: {:string, :generic}, enable_nested_fields: :boolean, fields: [{OpenApiTypesense.Field, :t}], + metadata: :map, name: {:string, :generic}, num_documents: :integer, symbols_to_index: [string: :generic], + synonym_sets: [string: :generic], token_separators: [string: :generic], voice_query_model: {OpenApiTypesense.VoiceQueryModelCollectionConfig, :t} ] diff --git a/lib/open_api_typesense/schemas/collection_schema.ex b/lib/open_api_typesense/schemas/collection_schema.ex index 118b926..0e3f9fa 100644 --- a/lib/open_api_typesense/schemas/collection_schema.ex +++ b/lib/open_api_typesense/schemas/collection_schema.ex @@ -8,15 +8,19 @@ defmodule OpenApiTypesense.CollectionSchema do default_sorting_field: String.t(), enable_nested_fields: boolean, fields: [OpenApiTypesense.Field.t()], + metadata: map, name: String.t(), symbols_to_index: [String.t()], + synonym_sets: [String.t()], token_separators: [String.t()], voice_query_model: OpenApiTypesense.VoiceQueryModelCollectionConfig.t() } defstruct [ :fields, + :metadata, :name, + :synonym_sets, default_sorting_field: "", enable_nested_fields: false, symbols_to_index: [], @@ -69,8 +73,10 @@ defmodule OpenApiTypesense.CollectionSchema do default_sorting_field: {:string, :generic}, enable_nested_fields: :boolean, fields: [{OpenApiTypesense.Field, :t}], + metadata: :map, name: {:string, :generic}, symbols_to_index: [string: :generic], + synonym_sets: [string: :generic], token_separators: [string: :generic], voice_query_model: {OpenApiTypesense.VoiceQueryModelCollectionConfig, :t} ] diff --git a/lib/open_api_typesense/schemas/collection_update_schema.ex b/lib/open_api_typesense/schemas/collection_update_schema.ex index 6e5f959..dd72b08 100644 --- a/lib/open_api_typesense/schemas/collection_update_schema.ex +++ b/lib/open_api_typesense/schemas/collection_update_schema.ex @@ -4,9 +4,13 @@ defmodule OpenApiTypesense.CollectionUpdateSchema do """ use OpenApiTypesense.Encoder - @type t :: %__MODULE__{fields: [OpenApiTypesense.Field.t()]} + @type t :: %__MODULE__{ + fields: [OpenApiTypesense.Field.t()], + metadata: map, + synonym_sets: [String.t()] + } - defstruct [:fields] + defstruct [:fields, :metadata, :synonym_sets] defimpl(Poison.Decoder, for: OpenApiTypesense.CollectionUpdateSchema) do def decode(value, %{as: struct}) do @@ -49,6 +53,6 @@ defmodule OpenApiTypesense.CollectionUpdateSchema do def __fields__(type \\ :t) def __fields__(:t) do - [fields: [{OpenApiTypesense.Field, :t}]] + [fields: [{OpenApiTypesense.Field, :t}], metadata: :map, synonym_sets: [string: :generic]] end end diff --git a/lib/open_api_typesense/schemas/drop_tokens_mode.ex b/lib/open_api_typesense/schemas/drop_tokens_mode.ex new file mode 100644 index 0000000..ab63c69 --- /dev/null +++ b/lib/open_api_typesense/schemas/drop_tokens_mode.ex @@ -0,0 +1,18 @@ +defmodule OpenApiTypesense.DropTokensMode do + @moduledoc """ + Provides struct and type for a DropTokensMode + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{match: String.t()} + + defstruct [:match] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [match: {:enum, ["right_to_left", "left_to_right", "both_sides:3"]}] + end +end diff --git a/lib/open_api_typesense/schemas/multi_search_collection_parameters.ex b/lib/open_api_typesense/schemas/multi_search_collection_parameters.ex index aec0760..a263376 100644 --- a/lib/open_api_typesense/schemas/multi_search_collection_parameters.ex +++ b/lib/open_api_typesense/schemas/multi_search_collection_parameters.ex @@ -10,8 +10,9 @@ defmodule OpenApiTypesense.MultiSearchCollectionParameters do conversation: boolean, conversation_id: String.t(), conversation_model_id: String.t(), - drop_tokens_mode: String.t(), + drop_tokens_mode: OpenApiTypesense.DropTokensMode.t(), drop_tokens_threshold: integer, + enable_analytics: boolean, enable_overrides: boolean, enable_synonyms: boolean, enable_typos_for_alpha_numerical_tokens: boolean, @@ -132,7 +133,8 @@ defmodule OpenApiTypesense.MultiSearchCollectionParameters do :vector_query, :voice_query, :"x-typesense-api-key", - drop_tokens_mode: "right_to_left", + drop_tokens_mode: %OpenApiTypesense.DropTokensMode{}, + enable_analytics: true, enable_overrides: false, enable_typos_for_numerical_tokens: true, pre_segmented_query: false, @@ -153,8 +155,9 @@ defmodule OpenApiTypesense.MultiSearchCollectionParameters do conversation: :boolean, conversation_id: {:string, :generic}, conversation_model_id: {:string, :generic}, - drop_tokens_mode: {:string, :generic}, + drop_tokens_mode: {OpenApiTypesense.DropTokensMode, :t}, drop_tokens_threshold: :integer, + enable_analytics: :boolean, enable_overrides: :boolean, enable_synonyms: :boolean, enable_typos_for_alpha_numerical_tokens: :boolean, diff --git a/lib/open_api_typesense/schemas/multi_search_result_item.ex b/lib/open_api_typesense/schemas/multi_search_result_item.ex index 4fcb922..af32fc8 100644 --- a/lib/open_api_typesense/schemas/multi_search_result_item.ex +++ b/lib/open_api_typesense/schemas/multi_search_result_item.ex @@ -13,11 +13,13 @@ defmodule OpenApiTypesense.MultiSearchResultItem do found_docs: integer, grouped_hits: [OpenApiTypesense.SearchGroupedHit.t()], hits: [OpenApiTypesense.SearchResultHit.t()], + metadata: map, out_of: integer, page: integer, - request_params: map, + request_params: OpenApiTypesense.SearchRequestParams.t(), search_cutoff: boolean, - search_time_ms: integer + search_time_ms: integer, + union_request_params: [OpenApiTypesense.SearchRequestParams.t()] } defstruct [ @@ -28,12 +30,14 @@ defmodule OpenApiTypesense.MultiSearchResultItem do :found_docs, :grouped_hits, :hits, + :metadata, :out_of, :page, - :request_params, :search_cutoff, :search_time_ms, - conversation: %OpenApiTypesense.SearchResultConversation{} + :union_request_params, + conversation: %OpenApiTypesense.SearchResultConversation{}, + request_params: %OpenApiTypesense.SearchRequestParams{} ] defimpl(Poison.Decoder, for: OpenApiTypesense.MultiSearchResultItem) do @@ -86,11 +90,13 @@ defmodule OpenApiTypesense.MultiSearchResultItem do found_docs: :integer, grouped_hits: [{OpenApiTypesense.SearchGroupedHit, :t}], hits: [{OpenApiTypesense.SearchResultHit, :t}], + metadata: :map, out_of: :integer, page: :integer, - request_params: :map, + request_params: {OpenApiTypesense.SearchRequestParams, :t}, search_cutoff: :boolean, - search_time_ms: :integer + search_time_ms: :integer, + union_request_params: [{OpenApiTypesense.SearchRequestParams, :t}] ] end end diff --git a/lib/open_api_typesense/schemas/multi_search_searches_parameter.ex b/lib/open_api_typesense/schemas/multi_search_searches_parameter.ex index 30822ca..cbbd6c5 100644 --- a/lib/open_api_typesense/schemas/multi_search_searches_parameter.ex +++ b/lib/open_api_typesense/schemas/multi_search_searches_parameter.ex @@ -9,7 +9,7 @@ defmodule OpenApiTypesense.MultiSearchSearchesParameter do union: boolean } - defstruct [:searches, :union] + defstruct [:searches, union: false] defimpl(Poison.Decoder, for: OpenApiTypesense.MultiSearchSearchesParameter) do def decode(value, %{as: struct}) do diff --git a/lib/open_api_typesense/schemas/nl_search_model_create_schema.ex b/lib/open_api_typesense/schemas/nl_search_model_create_schema.ex new file mode 100644 index 0000000..b6e37f9 --- /dev/null +++ b/lib/open_api_typesense/schemas/nl_search_model_create_schema.ex @@ -0,0 +1,78 @@ +defmodule OpenApiTypesense.NLSearchModelCreateSchema do + @moduledoc """ + Provides struct and type for a NLSearchModelCreateSchema + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + access_token: String.t(), + account_id: String.t(), + api_key: String.t(), + api_url: String.t(), + api_version: String.t(), + client_id: String.t(), + client_secret: String.t(), + id: String.t(), + max_bytes: integer, + max_output_tokens: integer, + model_name: String.t(), + project_id: String.t(), + refresh_token: String.t(), + region: String.t(), + stop_sequences: [String.t()], + system_prompt: String.t(), + temperature: number, + top_k: integer, + top_p: number + } + + defstruct [ + :access_token, + :account_id, + :api_key, + :api_url, + :api_version, + :client_id, + :client_secret, + :id, + :max_bytes, + :max_output_tokens, + :model_name, + :project_id, + :refresh_token, + :region, + :stop_sequences, + :system_prompt, + :temperature, + :top_k, + :top_p + ] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + access_token: {:string, :generic}, + account_id: {:string, :generic}, + api_key: {:string, :generic}, + api_url: {:string, :generic}, + api_version: {:string, :generic}, + client_id: {:string, :generic}, + client_secret: {:string, :generic}, + id: {:string, :generic}, + max_bytes: :integer, + max_output_tokens: :integer, + model_name: {:string, :generic}, + project_id: {:string, :generic}, + refresh_token: {:string, :generic}, + region: {:string, :generic}, + stop_sequences: [string: :generic], + system_prompt: {:string, :generic}, + temperature: :number, + top_k: :integer, + top_p: :number + ] + end +end diff --git a/lib/open_api_typesense/schemas/nl_search_model_delete_schema.ex b/lib/open_api_typesense/schemas/nl_search_model_delete_schema.ex new file mode 100644 index 0000000..6874d7f --- /dev/null +++ b/lib/open_api_typesense/schemas/nl_search_model_delete_schema.ex @@ -0,0 +1,18 @@ +defmodule OpenApiTypesense.NLSearchModelDeleteSchema do + @moduledoc """ + Provides struct and type for a NLSearchModelDeleteSchema + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{id: String.t()} + + defstruct [:id] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [id: {:string, :generic}] + end +end diff --git a/lib/open_api_typesense/schemas/nl_search_model_schema.ex b/lib/open_api_typesense/schemas/nl_search_model_schema.ex new file mode 100644 index 0000000..1f47896 --- /dev/null +++ b/lib/open_api_typesense/schemas/nl_search_model_schema.ex @@ -0,0 +1,18 @@ +defmodule OpenApiTypesense.NLSearchModelSchema do + @moduledoc """ + Provides struct and type for a NLSearchModelSchema + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{id: String.t()} + + defstruct [:id] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [id: {:string, :generic}] + end +end diff --git a/lib/open_api_typesense/schemas/search_parameters.ex b/lib/open_api_typesense/schemas/search_parameters.ex index 47f36bd..54cfdf4 100644 --- a/lib/open_api_typesense/schemas/search_parameters.ex +++ b/lib/open_api_typesense/schemas/search_parameters.ex @@ -9,8 +9,9 @@ defmodule OpenApiTypesense.SearchParameters do conversation: boolean, conversation_id: String.t(), conversation_model_id: String.t(), - drop_tokens_mode: String.t(), + drop_tokens_mode: OpenApiTypesense.DropTokensMode.t(), drop_tokens_threshold: integer, + enable_analytics: boolean, enable_highlight_v1: boolean, enable_overrides: boolean, enable_synonyms: boolean, @@ -43,6 +44,8 @@ defmodule OpenApiTypesense.SearchParameters do max_filter_by_candidates: integer, min_len_1typo: integer, min_len_2typo: integer, + nl_model_id: String.t(), + nl_query: boolean, num_typos: String.t(), offset: integer, override_tags: String.t(), @@ -67,6 +70,7 @@ defmodule OpenApiTypesense.SearchParameters do stopwords: String.t(), synonym_num_typos: integer, synonym_prefix: boolean, + synonym_sets: String.t(), text_match_type: String.t(), typo_tokens_threshold: integer, use_cache: boolean, @@ -109,6 +113,8 @@ defmodule OpenApiTypesense.SearchParameters do :max_filter_by_candidates, :min_len_1typo, :min_len_2typo, + :nl_model_id, + :nl_query, :num_typos, :offset, :override_tags, @@ -130,12 +136,14 @@ defmodule OpenApiTypesense.SearchParameters do :stopwords, :synonym_num_typos, :synonym_prefix, + :synonym_sets, :text_match_type, :typo_tokens_threshold, :use_cache, :vector_query, :voice_query, - drop_tokens_mode: "right_to_left", + drop_tokens_mode: %OpenApiTypesense.DropTokensMode{}, + enable_analytics: true, enable_highlight_v1: true, enable_overrides: false, enable_typos_for_numerical_tokens: true, @@ -154,8 +162,9 @@ defmodule OpenApiTypesense.SearchParameters do conversation: :boolean, conversation_id: {:string, :generic}, conversation_model_id: {:string, :generic}, - drop_tokens_mode: {:string, :generic}, + drop_tokens_mode: {OpenApiTypesense.DropTokensMode, :t}, drop_tokens_threshold: :integer, + enable_analytics: :boolean, enable_highlight_v1: :boolean, enable_overrides: :boolean, enable_synonyms: :boolean, @@ -188,6 +197,8 @@ defmodule OpenApiTypesense.SearchParameters do max_filter_by_candidates: :integer, min_len_1typo: :integer, min_len_2typo: :integer, + nl_model_id: {:string, :generic}, + nl_query: :boolean, num_typos: {:string, :generic}, offset: :integer, override_tags: {:string, :generic}, @@ -212,6 +223,7 @@ defmodule OpenApiTypesense.SearchParameters do stopwords: {:string, :generic}, synonym_num_typos: :integer, synonym_prefix: :boolean, + synonym_sets: {:string, :generic}, text_match_type: {:string, :generic}, typo_tokens_threshold: :integer, use_cache: :boolean, diff --git a/lib/open_api_typesense/schemas/search_request_params.ex b/lib/open_api_typesense/schemas/search_request_params.ex new file mode 100644 index 0000000..cbd6e48 --- /dev/null +++ b/lib/open_api_typesense/schemas/search_request_params.ex @@ -0,0 +1,28 @@ +defmodule OpenApiTypesense.SearchRequestParams do + @moduledoc """ + Provides struct and type for a SearchRequestParams + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{ + collection_name: String.t(), + per_page: integer, + q: String.t(), + voice_query: OpenApiTypesense.SearchRequestParamsVoiceQuery.t() + } + + defstruct [:collection_name, :per_page, :q, :voice_query] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [ + collection_name: {:string, :generic}, + per_page: :integer, + q: {:string, :generic}, + voice_query: {OpenApiTypesense.SearchRequestParamsVoiceQuery, :t} + ] + end +end diff --git a/lib/open_api_typesense/schemas/search_request_params_voice_query.ex b/lib/open_api_typesense/schemas/search_request_params_voice_query.ex new file mode 100644 index 0000000..b552c12 --- /dev/null +++ b/lib/open_api_typesense/schemas/search_request_params_voice_query.ex @@ -0,0 +1,18 @@ +defmodule OpenApiTypesense.SearchRequestParamsVoiceQuery do + @moduledoc """ + Provides struct and type for a SearchRequestParamsVoiceQuery + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{transcribed_query: String.t()} + + defstruct [:transcribed_query] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [transcribed_query: {:string, :generic}] + end +end diff --git a/lib/open_api_typesense/schemas/search_result.ex b/lib/open_api_typesense/schemas/search_result.ex index f27d384..944dc17 100644 --- a/lib/open_api_typesense/schemas/search_result.ex +++ b/lib/open_api_typesense/schemas/search_result.ex @@ -11,11 +11,13 @@ defmodule OpenApiTypesense.SearchResult do found_docs: integer, grouped_hits: [OpenApiTypesense.SearchGroupedHit.t()], hits: [OpenApiTypesense.SearchResultHit.t()], + metadata: map, out_of: integer, page: integer, - request_params: map, + request_params: OpenApiTypesense.SearchRequestParams.t(), search_cutoff: boolean, - search_time_ms: integer + search_time_ms: integer, + union_request_params: [OpenApiTypesense.SearchRequestParams.t()] } defstruct [ @@ -24,12 +26,14 @@ defmodule OpenApiTypesense.SearchResult do :found_docs, :grouped_hits, :hits, + :metadata, :out_of, :page, - :request_params, :search_cutoff, :search_time_ms, - conversation: %OpenApiTypesense.SearchResultConversation{} + :union_request_params, + conversation: %OpenApiTypesense.SearchResultConversation{}, + request_params: %OpenApiTypesense.SearchRequestParams{} ] defimpl(Poison.Decoder, for: OpenApiTypesense.SearchResult) do @@ -80,11 +84,13 @@ defmodule OpenApiTypesense.SearchResult do found_docs: :integer, grouped_hits: [{OpenApiTypesense.SearchGroupedHit, :t}], hits: [{OpenApiTypesense.SearchResultHit, :t}], + metadata: :map, out_of: :integer, page: :integer, - request_params: :map, + request_params: {OpenApiTypesense.SearchRequestParams, :t}, search_cutoff: :boolean, - search_time_ms: :integer + search_time_ms: :integer, + union_request_params: [{OpenApiTypesense.SearchRequestParams, :t}] ] end end diff --git a/lib/open_api_typesense/schemas/search_result_hit.ex b/lib/open_api_typesense/schemas/search_result_hit.ex index d054c17..2f4e55d 100644 --- a/lib/open_api_typesense/schemas/search_result_hit.ex +++ b/lib/open_api_typesense/schemas/search_result_hit.ex @@ -9,6 +9,8 @@ defmodule OpenApiTypesense.SearchResultHit do geo_distance_meters: OpenApiTypesense.SearchResultHitGeoDistanceMeters.t(), highlight: map, highlights: [OpenApiTypesense.SearchHighlight.t()], + hybrid_search_info: OpenApiTypesense.SearchResultHitHybridSearchInfo.t(), + search_index: integer, text_match: integer, text_match_info: OpenApiTypesense.SearchResultHitTextMatchInfo.t(), vector_distance: number @@ -19,6 +21,8 @@ defmodule OpenApiTypesense.SearchResultHit do :geo_distance_meters, :highlight, :highlights, + :hybrid_search_info, + :search_index, :text_match, :text_match_info, :vector_distance @@ -70,6 +74,8 @@ defmodule OpenApiTypesense.SearchResultHit do geo_distance_meters: {OpenApiTypesense.SearchResultHitGeoDistanceMeters, :t}, highlight: :map, highlights: [{OpenApiTypesense.SearchHighlight, :t}], + hybrid_search_info: {OpenApiTypesense.SearchResultHitHybridSearchInfo, :t}, + search_index: :integer, text_match: :integer, text_match_info: {OpenApiTypesense.SearchResultHitTextMatchInfo, :t}, vector_distance: :number diff --git a/lib/open_api_typesense/schemas/search_result_hit_hybrid_search_info.ex b/lib/open_api_typesense/schemas/search_result_hit_hybrid_search_info.ex new file mode 100644 index 0000000..09a07ed --- /dev/null +++ b/lib/open_api_typesense/schemas/search_result_hit_hybrid_search_info.ex @@ -0,0 +1,18 @@ +defmodule OpenApiTypesense.SearchResultHitHybridSearchInfo do + @moduledoc """ + Provides struct and type for a SearchResultHitHybridSearchInfo + """ + use OpenApiTypesense.Encoder + + @type t :: %__MODULE__{rank_fusion_score: number} + + defstruct [:rank_fusion_score] + + @doc false + @spec __fields__(atom) :: keyword + def __fields__(type \\ :t) + + def __fields__(:t) do + [rank_fusion_score: :number] + end +end diff --git a/lib/open_api_typesense/schemas/voice_query_model_collection_config.ex b/lib/open_api_typesense/schemas/voice_query_model_collection_config.ex index 4cefa64..fff0a59 100644 --- a/lib/open_api_typesense/schemas/voice_query_model_collection_config.ex +++ b/lib/open_api_typesense/schemas/voice_query_model_collection_config.ex @@ -6,7 +6,7 @@ defmodule OpenApiTypesense.VoiceQueryModelCollectionConfig do @type t :: %__MODULE__{model_name: String.t()} - defstruct model_name: "" + defstruct [:model_name] @doc false @spec __fields__(atom) :: keyword diff --git a/mix.exs b/mix.exs index 28d3665..dee8701 100644 --- a/mix.exs +++ b/mix.exs @@ -3,7 +3,7 @@ defmodule OpenApiTypesense.MixProject do @source_url "https://github.com/jaeyson/open_api_typesense" @hex_url "https://hexdocs.pm/open_api_typesense" - @version "1.0.4" + @version "1.1.0" def project do [ diff --git a/priv/car_data.json b/priv/car_data.json new file mode 100644 index 0000000..d3c0f50 --- /dev/null +++ b/priv/car_data.json @@ -0,0 +1,222 @@ +[ + { + "city_mpg": 13, + "driven_wheels": "rear wheel drive", + "engine_cylinders": 8, + "engine_fuel_type": "premium unleaded (recommended)", + "engine_hp": 707, + "highway_mpg": 22, + "car_data_id": 1480, + "id": "1480", + "make": "Dodge", + "market_category": ["Factory Tuner", "High-Performance"], + "model": "Charger", + "msrp": 65945, + "number_of_doors": 4, + "popularity": 1851, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Large", + "vehicle_style": "Sedan", + "year": 2017 + }, + { + "city_mpg": 20, + "driven_wheels": "front wheel drive", + "engine_cylinders": 4, + "engine_fuel_type": "regular unleaded", + "engine_hp": 140, + "highway_mpg": 30, + "car_data_id": 1481, + "id": "1481", + "make": "Honda", + "market_category": ["Hatchback", "Crossover"], + "model": "Civic", + "msrp": 22500, + "number_of_doors": 4, + "popularity": 4500, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Compact", + "vehicle_style": "Hatchback", + "year": 2022 + }, + { + "city_mpg": 16, + "driven_wheels": "all wheel drive", + "engine_cylinders": 6, + "engine_fuel_type": "premium unleaded (required)", + "engine_hp": 335, + "highway_mpg": 24, + "car_data_id": 1482, + "id": "1482", + "make": "Audi", + "market_category": ["Luxury", "Performance"], + "model": "A6", + "msrp": 55900, + "number_of_doors": 4, + "popularity": 3106, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Midsize", + "vehicle_style": "Sedan", + "year": 2023 + }, + { + "city_mpg": 15, + "driven_wheels": "rear wheel drive", + "engine_cylinders": 8, + "engine_fuel_type": "premium unleaded (recommended)", + "engine_hp": 455, + "highway_mpg": 25, + "car_data_id": 1483, + "id": "1483", + "make": "Chevrolet", + "market_category": ["Muscle", "High-Performance"], + "model": "Camaro", + "msrp": 38000, + "number_of_doors": 2, + "popularity": 1385, + "transmission_type": "MANUAL", + "vehicle_size": "Midsize", + "vehicle_style": "Coupe", + "year": 2021 + }, + { + "city_mpg": 18, + "driven_wheels": "four wheel drive", + "engine_cylinders": 6, + "engine_fuel_type": "regular unleaded", + "engine_hp": 285, + "highway_mpg": 23, + "car_data_id": 1484, + "id": "1484", + "make": "Jeep", + "market_category": ["Crossover", "Off-road"], + "model": "Wrangler", + "msrp": 35000, + "number_of_doors": 4, + "popularity": 4200, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Compact", + "vehicle_style": "SUV", + "year": 2023 + }, + { + "city_mpg": 25, + "driven_wheels": "front wheel drive", + "engine_cylinders": 4, + "engine_fuel_type": "regular unleaded", + "engine_hp": 185, + "highway_mpg": 35, + "car_data_id": 1485, + "id": "1485", + "make": "Hyundai", + "market_category": ["Economy"], + "model": "Elantra", + "msrp": 20500, + "number_of_doors": 4, + "popularity": 1800, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Compact", + "vehicle_style": "Sedan", + "year": 2022 + }, + { + "city_mpg": 19, + "driven_wheels": "rear wheel drive", + "engine_cylinders": 6, + "engine_fuel_type": "premium unleaded (recommended)", + "engine_hp": 255, + "highway_mpg": 28, + "car_data_id": 1486, + "id": "1486", + "make": "BMW", + "market_category": ["Luxury", "Performance"], + "model": "3 Series", + "msrp": 42000, + "number_of_doors": 4, + "popularity": 3916, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Compact", + "vehicle_style": "Sedan", + "year": 2023 + }, + { + "city_mpg": 14, + "driven_wheels": "all wheel drive", + "engine_cylinders": 8, + "engine_fuel_type": "premium unleaded (required)", + "engine_hp": 560, + "highway_mpg": 21, + "car_data_id": 1487, + "id": "1487", + "make": "Porsche", + "market_category": ["Luxury", "High-Performance"], + "model": "Cayenne", + "msrp": 80000, + "number_of_doors": 4, + "popularity": 1715, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Midsize", + "vehicle_style": "SUV", + "year": 2022 + }, + { + "city_mpg": 22, + "driven_wheels": "front wheel drive", + "engine_cylinders": 4, + "engine_fuel_type": "regular unleaded", + "engine_hp": 200, + "highway_mpg": 31, + "car_data_id": 1488, + "id": "1488", + "make": "Volkswagen", + "market_category": ["Sport", "Hatchback"], + "model": "GTI", + "msrp": 31000, + "number_of_doors": 4, + "popularity": 873, + "transmission_type": "MANUAL", + "vehicle_size": "Compact", + "vehicle_style": "Hatchback", + "year": 2023 + }, + { + "city_mpg": 17, + "driven_wheels": "all wheel drive", + "engine_cylinders": 6, + "engine_fuel_type": "regular unleaded", + "engine_hp": 290, + "highway_mpg": 24, + "car_data_id": 1489, + "id": "1489", + "make": "Subaru", + "market_category": ["Off-road", "Family"], + "model": "Outback", + "msrp": 29000, + "number_of_doors": 4, + "popularity": 640, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Midsize", + "vehicle_style": "Wagon", + "year": 2022 + }, + { + "city_mpg": 28, + "driven_wheels": "front wheel drive", + "engine_cylinders": 4, + "engine_fuel_type": "regular unleaded", + "engine_hp": 160, + "highway_mpg": 38, + "car_data_id": 1490, + "id": "1490", + "make": "Toyota", + "market_category": ["Economy", "Hybrid"], + "model": "Prius", + "msrp": 26000, + "number_of_doors": 4, + "popularity": 2031, + "transmission_type": "AUTOMATIC", + "vehicle_size": "Compact", + "vehicle_style": "Hatchback", + "year": 2023 + } +] diff --git a/priv/open_api.yml b/priv/open_api.yml index df900b7..2ecf471 100644 --- a/priv/open_api.yml +++ b/priv/open_api.yml @@ -2,7 +2,23 @@ openapi: 3.0.3 info: title: Typesense API description: "An open source search engine for building delightful search experiences." - version: '28.0' + version: '30.0' + license: + name: GPL-3.0 + url: https://opensource.org/licenses/GPL-3.0 +servers: + - url: "{protocol}://{hostname}:{port}" + description: Typesense Server + variables: + protocol: + default: http + description: The protocol of your Typesense server + hostname: + default: localhost + description: The hostname of your Typesense server + port: + default: "8108" + description: The port of your Typesense server externalDocs: description: Find out more about Typesense url: https://typesense.org @@ -66,6 +82,12 @@ tags: externalDocs: description: Find out more url: https://typesense.org/docs/28.0/api/stemming.html + - name: nl_search_models + description: Manage NL search models + externalDocs: + description: Find out more + url: https://typesense.org/docs/29.0/api/natural-language-search.html + paths: /collections: get: @@ -1229,6 +1251,7 @@ paths: tags: - conversations post: + summary: Create a conversation model description: Create a Conversation Model operationId: createConversationModel requestBody: @@ -1238,7 +1261,7 @@ paths: $ref: '#/components/schemas/ConversationModelCreateSchema' required: true responses: - '200': + '201': content: application/json: schema: @@ -1249,7 +1272,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/ApiResponse" + $ref: '#/components/schemas/ApiResponse' '401': description: Missing API key content: @@ -1753,21 +1776,17 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiResponse" - /operations/db/compact: + /operations/cache/clear: post: tags: - operations - summary: Compaction of the underlying RocksDB database + summary: Clear the cached responses of search requests in the LRU cache. description: - Typesense uses RocksDB to store your documents on the disk. If you do - frequent writes or updates, you could benefit from running a compaction - of the underlying RocksDB database. This could reduce the size of the - database and decrease read latency. While the database will not block - during this operation, we recommend running it during off-peak hours. - operationId: compact + Clear the cached responses of search requests that are sent with `use_cache` parameter in the LRU cache. + operationId: clearCache responses: '200': - description: Compacting the database + description: Clear cache succeeded. content: application/json: schema: @@ -1778,18 +1797,18 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiResponse" - /operations/cache/clear: + /operations/db/compact: post: tags: - operations - summary: Clears the cache + summary: Compacting the on-disk database description: - Responses of search requests that are sent with use_cache parameter are - cached in a LRU cache. Clears cache completely. - operationId: clearCache + Typesense uses RocksDB to store your documents on the disk. If you do frequent writes or updates, you could benefit from running a compaction of the underlying RocksDB database. + This could reduce the size of the database and decrease read latency. While the database will not block during this operation, we recommend running it during off-peak hours. + operationId: compactDb responses: '200': - description: Cache cleared + description: Compacting the on-disk database succeeded. content: application/json: schema: @@ -1804,17 +1823,24 @@ paths: post: tags: - operations - summary: Enable logging of requests that take over a defined threshold of time. - description: >- - Slow requests are logged to the primary log file, with the prefix SLOW - REQUEST. Default is -1 which disables slow request logging. - operationId: config + summary: Toggle Slow Request Log + description: + Enable logging of requests that take over a defined threshold of time. + Default is `-1` which disables slow request logging. + Slow requests are logged to the primary log file, with the prefix SLOW REQUEST. + operationId: toggleSlowRequestLog requestBody: - description: Define threshold in ms for logging of requests content: application/json: schema: - $ref: "#/components/schemas/ConfigSchema" + type: object + properties: + log-slow-requests-time-ms: + type: integer + required: + - log-slow-requests-time-ms + example: | + {"log-slow-requests-time-ms": 2000} responses: '201': description: Updated slow request log @@ -1890,17 +1916,17 @@ paths: tags: - analytics summary: Create an analytics event - description: Sending events for analytics e.g rank search results based on popularity. + description: Submit a single analytics event. The event must correspond to an existing analytics rule by name. operationId: createAnalyticsEvent requestBody: - description: The Analytics event to be created + description: The analytics event to be created content: application/json: schema: - $ref: '#/components/schemas/AnalyticsEventCreateSchema' + $ref: '#/components/schemas/AnalyticsEvent' required: true responses: - '201': + '200': description: Analytics event successfully created content: application/json: @@ -1918,28 +1944,105 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiResponse" + get: + tags: + - analytics + summary: Retrieve analytics events + description: Retrieve the most recent events for a user and rule. + operationId: getAnalyticsEvents + parameters: + - name: user_id + in: query + required: true + schema: + type: string + - name: name + in: query + description: Analytics rule name + required: true + schema: + type: string + - name: n + in: query + description: Number of events to return (max 1000) + required: true + schema: + type: integer + responses: + '200': + description: Events fetched + content: + application/json: + schema: + $ref: '#/components/schemas/AnalyticsEventsResponse' + '400': + description: Bad request, see error message for details + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + /analytics/flush: + post: + tags: + - analytics + summary: Flush in-memory analytics to disk + description: Triggers a flush of analytics data to persistent storage. + operationId: flushAnalytics + responses: + '200': + description: Flush triggered + content: + application/json: + schema: + $ref: '#/components/schemas/AnalyticsEventCreateResponse' + /analytics/status: + get: + tags: + - analytics + summary: Get analytics subsystem status + description: Returns sizes of internal analytics buffers and queues. + operationId: getAnalyticsStatus + responses: + '200': + description: Status fetched + content: + application/json: + schema: + $ref: '#/components/schemas/AnalyticsStatus' /analytics/rules: post: tags: - analytics - summary: Creates an analytics rule - description: - When an analytics rule is created, we give it a name and describe the type, the source collections and the destination collection. + summary: Create analytics rule(s) + description: Create one or more analytics rules. You can send a single rule object or an array of rule objects. operationId: createAnalyticsRule requestBody: - description: The Analytics rule to be created + description: The analytics rule(s) to be created content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleSchema" + oneOf: + - $ref: "#/components/schemas/AnalyticsRuleCreate" + - type: array + items: + $ref: "#/components/schemas/AnalyticsRuleCreate" required: true responses: - '201': - description: Analytics rule successfully created + '200': + description: Analytics rule(s) successfully created content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleSchema" + oneOf: + - $ref: "#/components/schemas/AnalyticsRule" + - type: array + items: + anyOf: + - $ref: "#/components/schemas/AnalyticsRule" + - type: object + properties: + error: + type: string '400': description: Bad request, see error message for details content: @@ -1961,17 +2064,25 @@ paths: get: tags: - analytics - summary: Retrieves all analytics rules - description: - Retrieve the details of all analytics rules + summary: Retrieve analytics rules + description: Retrieve all analytics rules. Use the optional rule_tag filter to narrow down results. operationId: retrieveAnalyticsRules + parameters: + - in: query + name: rule_tag + schema: + type: string + required: false + description: Filter rules by rule_tag responses: '200': description: Analytics rules fetched content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRulesRetrieveSchema" + type: array + items: + $ref: "#/components/schemas/AnalyticsRule" '401': description: "Missing API key" content: @@ -1998,7 +2109,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleUpsertSchema" + $ref: "#/components/schemas/AnalyticsRuleUpdate" required: true responses: '200': @@ -2006,7 +2117,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleSchema" + $ref: "#/components/schemas/AnalyticsRule" '400': description: Bad request, see error message for details content: @@ -2039,7 +2150,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleSchema" + $ref: "#/components/schemas/AnalyticsRule" '401': description: "Missing API key" content: @@ -2072,7 +2183,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/AnalyticsRuleDeleteResponse" + $ref: "#/components/schemas/AnalyticsRule" '401': description: "Missing API key" content: @@ -2348,7 +2459,7 @@ paths: schema: $ref: '#/components/schemas/PresetSchema' '400': - description: Bad request, see error message for details. + description: Bad request, see error message for details content: application/json: schema: @@ -2501,6 +2612,177 @@ paths: application/json: schema: $ref: "#/components/schemas/ApiResponse" + /nl_search_models: + get: + tags: + - nl_search_models + summary: List all NL search models + description: Retrieve all NL search models. + operationId: retrieveAllNLSearchModels + responses: + '200': + description: List of all NL search models + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NLSearchModelSchema' + '401': + description: "Missing API key" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + post: + tags: + - nl_search_models + summary: Create a NL search model + description: Create a new NL search model. + operationId: createNLSearchModel + requestBody: + description: The NL search model to be created + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelCreateSchema' + required: true + responses: + '201': + description: NL search model successfully created + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelSchema' + '400': + description: Bad request, see error message for details + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '401': + description: "Missing API key" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + '409': + description: Model already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + /nl_search_models/{modelId}: + get: + tags: + - nl_search_models + summary: Retrieve a NL search model + description: Retrieve a specific NL search model by its ID. + operationId: retrieveNLSearchModel + parameters: + - name: modelId + in: path + description: The ID of the NL search model to retrieve + required: true + schema: + type: string + responses: + '200': + description: NL search model fetched + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelSchema' + '401': + description: "Missing API key" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + '404': + description: NL search model not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + put: + tags: + - nl_search_models + summary: Update a NL search model + description: Update an existing NL search model. + operationId: updateNLSearchModel + parameters: + - name: modelId + in: path + description: The ID of the NL search model to update + required: true + schema: + type: string + requestBody: + description: The NL search model fields to update + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelUpdateSchema' + required: true + responses: + '200': + description: NL search model successfully updated + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelSchema' + '401': + description: "Missing API key" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + '400': + description: Bad request, see error message for details + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + '404': + description: NL search model not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + delete: + tags: + - nl_search_models + summary: Delete a NL search model + description: Delete a specific NL search model by its ID. + operationId: deleteNLSearchModel + parameters: + - name: modelId + in: path + description: The ID of the NL search model to delete + required: true + schema: + type: string + responses: + '200': + description: NL search model successfully deleted + content: + application/json: + schema: + $ref: '#/components/schemas/NLSearchModelDeleteSchema' + '401': + description: "Missing API key" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiResponse" + '404': + description: NL search model not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + components: schemas: CollectionSchema: @@ -2548,6 +2830,12 @@ components: minLength: 1 maxLength: 1 default: [] + synonym_sets: + type: array + description: List of synonym set names to associate with this collection + items: + type: string + example: "synonym_set_1" enable_nested_fields: type: boolean description: @@ -2568,6 +2856,10 @@ components: default: [] voice_query_model: $ref: "#/components/schemas/VoiceQueryModelCollectionConfig" + metadata: + type: object + description: > + Optional details about the collection, e.g., when it was created, who created it etc. CollectionUpdateSchema: required: - fields @@ -2588,6 +2880,16 @@ components: facet: true items: $ref: "#/components/schemas/Field" + synonym_sets: + type: array + description: List of synonym set names to associate with this collection + items: + type: string + example: "synonym_set_1" + metadata: + type: object + description: > + Optional details about the collection, e.g., when it was created, who created it etc. CollectionResponse: allOf: - $ref: "#/components/schemas/CollectionSchema" @@ -2734,18 +3036,7 @@ components: properties: model_name: type: string - default: "" example: "ts/whisper/base.en" - ConfigSchema: - type: object - required: - - log_slow_requests_time_ms - properties: - log_slow_requests_time_ms: - type: integer - description: - Enable logging of requests that take over a defined threshold of - time in ms. CollectionAliasSchema: type: object required: @@ -2811,25 +3102,36 @@ components: items: $ref: "#/components/schemas/SearchResultHit" request_params: + $ref: "#/components/schemas/SearchRequestParams" + conversation: + $ref: "#/components/schemas/SearchResultConversation" + union_request_params: + type: array + description: Returned only for union query response. + items: + $ref: "#/components/schemas/SearchRequestParams" + metadata: + type: object + description: Custom JSON object that can be returned in the search response + additionalProperties: true + SearchRequestParams: + type: object + required: + - collection_name + - q + - per_page + properties: + collection_name: + type: string + q: + type: string + per_page: + type: integer + voice_query: type: object - required: - - collection_name - - q - - per_page properties: - collection_name: + transcribed_query: type: string - q: - type: string - per_page: - type: integer - voice_query: - type: object - properties: - transcribed_query: - type: string - conversation: - $ref: "#/components/schemas/SearchResultConversation" SearchResultConversation: type: object required: @@ -2912,6 +3214,17 @@ components: type: number format: float description: Distance between the query vector and matching document's vector value + hybrid_search_info: + type: object + description: Information about hybrid search scoring + properties: + rank_fusion_score: + type: number + format: float + description: Combined score from rank fusion of text and vector search + search_index: + type: integer + description: Returned only for union query response. Indicates the index of the query which this document matched to. example: highlights: company_name: @@ -3231,24 +3544,6 @@ components: x-go-type: "[]*ApiKey" items: $ref: "#/components/schemas/ApiKey" - ScopedKeyParameters: - type: object - properties: - filter_by: - type: string - expires_at: - type: integer - format: int64 - SnapshotParameters: - type: object - properties: - snapshot_path: - type: string - ErrorResponse: - type: object - properties: - message: - type: string MultiSearchResult: type: object required: @@ -3286,6 +3581,14 @@ components: against. Multiple fields are separated with a comma. type: string + nl_query: + description: Whether to use natural language processing to parse the query. + type: boolean + + nl_model_id: + description: The ID of the natural language model to use. + type: string + query_by_weights: description: The relative weight to give each `query_by` field when ranking results. @@ -3333,7 +3636,7 @@ components: filter_by: description: - Filter conditions for refining youropen api validator search results. Separate + Filter conditions for refining your open api validator search results. Separate multiple conditions with &&. type: string example: "num_employees:>100 && country: [USA, UK]" @@ -3455,12 +3758,24 @@ components: type: boolean default: true + enable_analytics: + description: > + Flag for enabling/disabling analytics aggregation for specific search + queries (for e.g. those originating from a test script). + type: boolean + default: true + snippet_threshold: description: > Field values under this length will be fully highlighted, instead of showing a snippet of relevant portion. Default: 30 type: integer + synonym_sets: + type: string + description: List of synonym set names to associate with this search query + example: "synonym_set_1,synonym_set_2" + drop_tokens_threshold: description: > If the number of results found for a specific query is less than @@ -3469,13 +3784,7 @@ components: are dropped first. Set to 0 to disable. Default: 10 type: integer drop_tokens_mode: - description: > - Dictates the direction in which the words in the query must be dropped when the original words in the query do not appear in any document. - Values: right_to_left (default), left_to_right, both_sides:3 - A note on both_sides:3 - for queries upto 3 tokens (words) in length, this mode will drop tokens from both sides and exhaustively rank all matching results. - If query length is greater than 3 words, Typesense will just fallback to default behavior of right_to_left - type: string - default: "right_to_left" + $ref: "#/components/schemas/DropTokensMode" typo_tokens_threshold: description: > If the number of results found for a specific query is less than this number, @@ -3852,13 +4161,7 @@ components: are dropped first. Set to 0 to disable. Default: 10 type: integer drop_tokens_mode: - description: > - Dictates the direction in which the words in the query must be dropped when the original words in the query do not appear in any document. - Values: right_to_left (default), left_to_right, both_sides:3 - A note on both_sides:3 - for queries upto 3 tokens (words) in length, this mode will drop tokens from both sides and exhaustively rank all matching results. - If query length is greater than 3 words, Typesense will just fallback to default behavior of right_to_left - type: string - default: "right_to_left" + $ref: "#/components/schemas/DropTokensMode" typo_tokens_threshold: description: > If the number of results found for a specific query is less than this number, @@ -3878,6 +4181,14 @@ components: type: boolean description: > If you have some synonyms defined but want to disable all of them for a particular search query, set enable_synonyms to false. Default: true + + enable_analytics: + description: > + Flag for enabling/disabling analytics aggregation for specific search + queries (for e.g. those originating from a test script). + type: boolean + default: true + synonym_prefix: type: boolean description: > @@ -4049,6 +4360,7 @@ components: properties: union: type: boolean + default: false description: When true, merges the search results from each search query into a single ordered set of hits. searches: type: array @@ -4115,105 +4427,133 @@ components: properties: ok: type: boolean - AnalyticsEventCreateSchema: + AnalyticsEvent: type: object required: - - type - name + - event_type - data properties: - type: - type: string name: type: string + description: Name of the analytics rule this event corresponds to + event_type: + type: string + description: Type of event (e.g., click, conversion, query, visit) data: type: object - AnalyticsRuleUpsertSchema: - type: object - required: - - type - - params - properties: - type: - type: string - enum: - - popular_queries - - nohits_queries - - counter - params: - $ref: "#/components/schemas/AnalyticsRuleParameters" - AnalyticsRuleParameters: - type: object - required: - - source - - destination - properties: - source: - $ref: '#/components/schemas/AnalyticsRuleParametersSource' - destination: - $ref: '#/components/schemas/AnalyticsRuleParametersDestination' - limit: - type: integer - expand_query: - type: boolean - AnalyticsRuleParametersSource: + description: Event payload + properties: + user_id: + type: string + doc_id: + type: string + doc_ids: + type: array + items: + type: string + q: + type: string + analytics_tag: + type: string + AnalyticsEventsResponse: type: object required: - - collections + - events properties: - collections: - type: array - items: - type: string events: type: array items: type: object - required: - - type - - weight - - name properties: - type: - type: string - weight: - type: number - format: float - name: - type: string - AnalyticsRuleParametersDestination: + name: { type: string } + event_type: { type: string } + collection: { type: string } + timestamp: { type: integer, format: int64 } + user_id: { type: string } + doc_id: { type: string } + doc_ids: + type: array + items: { type: string } + query: { type: string } + AnalyticsRuleCreate: type: object required: + - name + - type - collection + - event_type properties: + name: + type: string + type: + type: string + enum: [popular_queries, nohits_queries, counter, log] collection: type: string - counter_field: + event_type: + type: string + rule_tag: type: string - AnalyticsRuleDeleteResponse: + params: + type: object + properties: + destination_collection: + type: string + limit: + type: integer + capture_search_requests: + type: boolean + meta_fields: + type: array + items: { type: string } + expand_query: + type: boolean + counter_field: + type: string + weight: + type: integer + AnalyticsRuleUpdate: type: object - required: - - name + description: Fields allowed to update on an analytics rule properties: name: type: string - AnalyticsRuleSchema: - allOf: - - $ref: '#/components/schemas/AnalyticsRuleUpsertSchema' - - type: object - required: - - name + rule_tag: + type: string + params: + type: object properties: - name: + destination_collection: type: string - AnalyticsRulesRetrieveSchema: + limit: + type: integer + capture_search_requests: + type: boolean + meta_fields: + type: array + items: { type: string } + expand_query: + type: boolean + counter_field: + type: string + weight: + type: integer + AnalyticsRule: + allOf: + - $ref: '#/components/schemas/AnalyticsRuleCreate' + - type: object + AnalyticsStatus: type: object properties: - rules: - type: array - items: - $ref: "#/components/schemas/AnalyticsRuleSchema" - x-go-type: '[]*AnalyticsRuleSchema' + popular_prefix_queries: { type: integer } + nohits_prefix_queries: { type: integer } + log_prefix_queries: { type: integer } + query_log_events: { type: integer } + query_counter_events: { type: integer } + doc_log_events: { type: integer } + doc_counter_events: { type: integer } + APIStatsResponse: type: object properties: @@ -4339,12 +4679,6 @@ components: properties: name: type: string - # client libraries already have .create, .upsert,... methods so we omit the `action` param - DocumentIndexParameters: - type: object - properties: - dirty_values: - $ref: "#/components/schemas/DirtyValues" DirtyValues: type: string enum: [coerce_or_reject, coerce_or_drop, drop, reject] @@ -4352,8 +4686,19 @@ components: type: string enum: [create, update, upsert, emplace] DropTokensMode: - type: string - enum: [right_to_left, left_to_right, both_sides:3] + type: object + properties: + match: + type: string + description: > + Dictates the direction in which the words in the query must be dropped when the original words in the query do not appear in any document. + Values: right_to_left (default), left_to_right, both_sides:3 + A note on both_sides:3 - for queries up to 3 tokens (words) in length, this mode will drop tokens from both sides and exhaustively rank all matching results. + If query length is greater than 3 words, Typesense will just fallback to default behavior of right_to_left + enum: + - right_to_left + - left_to_right + - both_sides:3 ConversationModelCreateSchema: required: - model_name @@ -4445,8 +4790,171 @@ components: type: string description: The root form of the word example: person + NLSearchModelBase: + type: object + properties: + model_name: + type: string + description: Name of the NL model to use + api_key: + type: string + description: API key for the NL model service + api_url: + type: string + description: Custom API URL for the NL model service + max_bytes: + type: integer + description: Maximum number of bytes to process + temperature: + type: number + description: Temperature parameter for the NL model + system_prompt: + type: string + description: System prompt for the NL model + top_p: + type: number + description: Top-p parameter for the NL model (Google-specific) + top_k: + type: integer + description: Top-k parameter for the NL model (Google-specific) + stop_sequences: + type: array + items: + type: string + description: Stop sequences for the NL model (Google-specific) + api_version: + type: string + description: API version for the NL model service + project_id: + type: string + description: Project ID for GCP Vertex AI + access_token: + type: string + description: Access token for GCP Vertex AI + refresh_token: + type: string + description: Refresh token for GCP Vertex AI + client_id: + type: string + description: Client ID for GCP Vertex AI + client_secret: + type: string + description: Client secret for GCP Vertex AI + region: + type: string + description: Region for GCP Vertex AI + max_output_tokens: + type: integer + description: Maximum output tokens for GCP Vertex AI + account_id: + type: string + description: Account ID for Cloudflare-specific models + + NLSearchModelCreateSchema: + allOf: + - $ref: '#/components/schemas/NLSearchModelBase' + - type: object + properties: + id: + type: string + description: Optional ID for the NL search model + + NLSearchModelSchema: + allOf: + - $ref: '#/components/schemas/NLSearchModelCreateSchema' + - type: object + required: + - id + properties: + id: + type: string + description: ID of the NL search model + + NLSearchModelUpdateSchema: + $ref: '#/components/schemas/NLSearchModelCreateSchema' + + NLSearchModelDeleteSchema: + type: object + required: + - id + properties: + id: + type: string + description: ID of the deleted NL search model + + SynonymItemSchema: + type: object + required: + - id + - synonyms + properties: + id: + type: string + description: Unique identifier for the synonym item + synonyms: + type: array + description: Array of words that should be considered as synonyms + items: + type: string + root: + type: string + description: For 1-way synonyms, indicates the root word that words in the synonyms parameter map to + locale: + type: string + description: Locale for the synonym, leave blank to use the standard tokenizer + symbols_to_index: + type: array + description: By default, special characters are dropped from synonyms. Use this attribute to specify which special characters should be indexed as is + items: + type: string + + SynonymSetCreateSchema: + type: object + required: + - items + properties: + items: + type: array + description: Array of synonym items + items: + $ref: "#/components/schemas/SynonymItemSchema" + + SynonymSetSchema: + allOf: + - $ref: "#/components/schemas/SynonymSetCreateSchema" + - type: object + required: + - name + properties: + name: + type: string + description: Name of the synonym set + + SynonymSetsRetrieveSchema: + type: object + required: + - synonym_sets + properties: + synonym_sets: + type: array + description: Array of synonym sets + items: + $ref: "#/components/schemas/SynonymSetSchema" + + SynonymSetRetrieveSchema: + $ref: "#/components/schemas/SynonymSetCreateSchema" + + SynonymSetDeleteSchema: + type: object + required: + - name + properties: + name: + type: string + description: Name of the deleted synonym set + securitySchemes: api_key_header: type: apiKey name: X-TYPESENSE-API-KEY - in: header + in: header \ No newline at end of file diff --git a/test/connection_test.exs b/test/connection_test.exs index e4b206c..5255f6e 100644 --- a/test/connection_test.exs +++ b/test/connection_test.exs @@ -11,7 +11,7 @@ defmodule ConnectionTest do message: "Forbidden - a valid `x-typesense-api-key` header must be sent." } - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "new/0 using the default config to creates a connection struct" do assert Connection.new() === %Connection{ api_key: "xyz", @@ -25,7 +25,7 @@ defmodule ConnectionTest do } end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "new/1 with custom fields creates a connection struct" do conn = Connection.new(%{ @@ -47,7 +47,7 @@ defmodule ConnectionTest do } end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: wrong api key was configured" do conn = %{ host: "localhost", @@ -59,7 +59,7 @@ defmodule ConnectionTest do assert {:error, @forbidden} == Collections.get_collections(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: overriding config with a wrong API key" do conn = %{ host: "localhost", @@ -71,34 +71,34 @@ defmodule ConnectionTest do assert {:error, @forbidden} = Collections.get_collections(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: health check, with incorrect port number" do conn = %{api_key: "xyz", host: "localhost", port: 8100, scheme: "http"} assert {:error, "connection refused"} = Health.health(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: health check, with incorrect host" do conn = %{api_key: "xyz", host: "my_test_host", port: 8108, scheme: "http"} assert {:error, "non-existing domain"} = Health.health(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "new/1 with Connection struct" do conn = Connection.new() assert %Connection{} = Connection.new(conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "new/1 with empty map raises ArgumentError" do error = assert_raise ArgumentError, fn -> Connection.new(%{}) end assert error.message === "Missing required fields: [:api_key, :host, :port, :scheme]" end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "new/1 with invalid data type raises ArgumentError" do invalid_inputs = [ nil, diff --git a/test/custom_client_test.exs b/test/custom_client_test.exs index feb9578..2c7ce83 100644 --- a/test/custom_client_test.exs +++ b/test/custom_client_test.exs @@ -74,7 +74,7 @@ defmodule CustomClientTest do end) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "returns the configured options" do Application.put_env(:open_api_typesense, :options, finch: MyApp.CustomFinch, @@ -86,7 +86,7 @@ defmodule CustomClientTest do assert options === [finch: MyApp.CustomFinch, receive_timeout: 5_000] end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "returns an empty map if options is not configured" do Application.delete_env(:open_api_typesense, :options) @@ -95,7 +95,7 @@ defmodule CustomClientTest do assert options === nil end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "use another HTTP client" do map_conn = %{ api_key: "xyz", diff --git a/test/default_client_test.exs b/test/default_client_test.exs index 041ed7a..d125da8 100644 --- a/test/default_client_test.exs +++ b/test/default_client_test.exs @@ -7,7 +7,7 @@ defmodule DefaultClientTest do require Logger describe "request/2" do - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "default to req http client if no custom client set" do conn = Connection.new() @@ -27,7 +27,7 @@ defmodule DefaultClientTest do end describe "build_req_client/2" do - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "override req options through req field" do req = Client.build_req_client(Connection.new(), @@ -43,7 +43,7 @@ defmodule DefaultClientTest do end end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "get api key" do assert "xyz" = Client.api_key() end diff --git a/test/operations/analytics_test.exs b/test/operations/analytics_test.exs index 6abf9b8..387e9e0 100644 --- a/test/operations/analytics_test.exs +++ b/test/operations/analytics_test.exs @@ -2,6 +2,7 @@ defmodule AnalyticsTest do use ExUnit.Case, async: true alias OpenApiTypesense.Analytics + alias OpenApiTypesense.AnalyticsRule alias OpenApiTypesense.AnalyticsRuleSchema alias OpenApiTypesense.AnalyticsRulesRetrieveSchema alias OpenApiTypesense.ApiResponse @@ -78,7 +79,7 @@ defmodule AnalyticsTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: create analytics rule with non-existent collection", %{ conn: conn, map_conn: map_conn @@ -126,16 +127,16 @@ defmodule AnalyticsTest do } } - assert {:ok, %AnalyticsRuleSchema{name: ^name}} = + assert {:ok, %AnalyticsRule{name: ^name}} = Analytics.upsert_analytics_rule(name, body) - assert {:ok, %AnalyticsRuleSchema{name: ^name}} = + assert {:ok, %AnalyticsRule{name: ^name}} = Analytics.upsert_analytics_rule(name, body, []) - assert {:ok, %AnalyticsRuleSchema{name: ^name}} = + assert {:ok, %AnalyticsRule{name: ^name}} = Analytics.upsert_analytics_rule(name, body, conn: conn) - assert {:ok, %AnalyticsRuleSchema{name: ^name}} = + assert {:ok, %AnalyticsRule{name: ^name}} = Analytics.upsert_analytics_rule(name, body, conn: map_conn) end diff --git a/test/operations/collections_test.exs b/test/operations/collections_test.exs index 59dc748..d55e614 100644 --- a/test/operations/collections_test.exs +++ b/test/operations/collections_test.exs @@ -32,7 +32,7 @@ defmodule CollectionsTest do %{schema: schema, alias_name: "foo_bar", conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: clone a collection schema" do schema = %{ "name" => "vehicles", @@ -56,7 +56,7 @@ defmodule CollectionsTest do assert {:ok, _} = Collections.delete_collection(payload["name"]) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: create a collection", %{schema: schema, conn: conn, map_conn: map_conn} do name = schema["name"] @@ -72,7 +72,7 @@ defmodule CollectionsTest do Collections.get_collections() end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list collections", %{conn: conn, map_conn: map_conn} do assert {:ok, collections} = Collections.get_collections() assert length(collections) >= 0 @@ -85,7 +85,7 @@ defmodule CollectionsTest do assert {:ok, _} = Collections.get_collections(conn: map_conn, limit: 1) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: update an existing collection", %{conn: conn, map_conn: map_conn} do name = "burgers" @@ -118,7 +118,7 @@ defmodule CollectionsTest do Collections.delete_collection(name) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list empty aliases", %{conn: conn, map_conn: map_conn} do assert {:ok, %CollectionAliasesResponse{aliases: aliases}} = Collections.get_aliases() assert length(aliases) >= 0 @@ -127,7 +127,7 @@ defmodule CollectionsTest do assert {:ok, _} = Collections.get_aliases(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete a missing collection", %{conn: conn, map_conn: map_conn} do assert Collections.delete_collection("non-existing-collection") == {:error, @@ -142,7 +142,7 @@ defmodule CollectionsTest do Collections.delete_collection("xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: upsert an alias", %{ schema: schema, alias_name: alias_name, @@ -178,6 +178,16 @@ defmodule CollectionsTest do assert {:error, %ApiResponse{message: _}} = Collections.get_alias("xyz", conn: map_conn) end + @tag ["29.0": true] + test "error: get a non-existing alias (> v28.0)", %{conn: conn, map_conn: map_conn} do + assert Collections.get_alias("non-existing-alias") == + {:error, %ApiResponse{message: "Collection not found"}} + + assert {:error, %ApiResponse{message: _}} = Collections.get_alias("xyz", []) + assert {:error, %ApiResponse{message: _}} = Collections.get_alias("xyz", conn: conn) + assert {:error, %ApiResponse{message: _}} = Collections.get_alias("xyz", conn: map_conn) + end + @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: get a non-existing collection", %{conn: conn, map_conn: map_conn} do assert Collections.get_collection("non-existing-collection") == @@ -188,4 +198,15 @@ defmodule CollectionsTest do assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz", conn: conn) assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz", conn: map_conn) end + + @tag ["29.0": true] + test "error: get a non-existing collection (> v28.0)", %{conn: conn, map_conn: map_conn} do + assert Collections.get_collection("non-existing-collection") == + {:error, %ApiResponse{message: "Collection not found"}} + + assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz") + assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz", []) + assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz", conn: conn) + assert {:error, %ApiResponse{message: _}} = Collections.get_collection("xyz", conn: map_conn) + end end diff --git a/test/operations/conversations_test.exs b/test/operations/conversations_test.exs index db7c3ed..8805f63 100644 --- a/test/operations/conversations_test.exs +++ b/test/operations/conversations_test.exs @@ -34,7 +34,7 @@ defmodule ConversationsTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list conversation models", %{conn: conn, map_conn: map_conn} do assert {:ok, models} = Conversations.retrieve_all_conversation_models() assert length(models) >= 0 @@ -43,7 +43,7 @@ defmodule ConversationsTest do assert {:ok, _} = Conversations.retrieve_all_conversation_models(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: get a non-existent conversation model", %{conn: conn, map_conn: map_conn} do assert {:error, %ApiResponse{message: "Model not found"}} = Conversations.retrieve_conversation_model("non-existent") @@ -53,7 +53,7 @@ defmodule ConversationsTest do assert {:error, _} = Conversations.retrieve_conversation_model("xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete a conversation model", %{conn: conn, map_conn: map_conn} do assert {:error, %ApiResponse{message: "Model not found"}} = Conversations.delete_conversation_model("non-existent") @@ -63,7 +63,7 @@ defmodule ConversationsTest do assert {:error, _} = Conversations.delete_conversation_model("xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: create a conversation model with incorrect API key", %{ conn: conn, map_conn: map_conn @@ -94,7 +94,7 @@ defmodule ConversationsTest do assert {:error, _} = Conversations.create_conversation_model(body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: update a conversation model with incorrect API key", %{ conn: conn, map_conn: map_conn diff --git a/test/operations/curation_test.exs b/test/operations/curation_test.exs index 6832322..433f8ca 100644 --- a/test/operations/curation_test.exs +++ b/test/operations/curation_test.exs @@ -34,7 +34,7 @@ defmodule CurationTest do %{schema_name: name, conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: upsert search override", %{ schema_name: schema_name, conn: conn, @@ -67,7 +67,7 @@ defmodule CurationTest do Curation.upsert_search_override(schema_name, override_id, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete search override", %{ schema_name: schema_name, conn: conn, @@ -83,7 +83,7 @@ defmodule CurationTest do assert {:error, _} = Curation.delete_search_override(schema_name, "test", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list collection overrides", %{ schema_name: schema_name, conn: conn, diff --git a/test/operations/debug_test.exs b/test/operations/debug_test.exs index fe2c6bf..14ebaff 100644 --- a/test/operations/debug_test.exs +++ b/test/operations/debug_test.exs @@ -12,7 +12,7 @@ defmodule DebugTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list stopwords sets", %{conn: conn, map_conn: map_conn} do assert {:ok, %Debug{version: _}} = Debug.debug() assert {:ok, _} = Debug.debug([]) @@ -20,7 +20,7 @@ defmodule DebugTest do assert {:ok, _} = Debug.debug(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "field" do assert [version: {:string, :generic}] = Debug.__fields__(:debug_200_json_resp) end diff --git a/test/operations/documents_test.exs b/test/operations/documents_test.exs index a869c06..894d839 100644 --- a/test/operations/documents_test.exs +++ b/test/operations/documents_test.exs @@ -38,7 +38,7 @@ defmodule DocumentsTest do %{coll_name: name, conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: update a document", %{coll_name: coll_name} do body = %{ "shoes_id" => 12_299, @@ -57,7 +57,7 @@ defmodule DocumentsTest do Documents.update_document(coll_name, document_id, body) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: update a non-existent document", %{ coll_name: coll_name, conn: conn, @@ -81,7 +81,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.update_document(coll_name, document_id, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: search a document", %{coll_name: coll_name, conn: conn, map_conn: map_conn} do body = [ @@ -123,7 +123,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.search_collection(coll_name, List.flatten([conn: map_conn], opts)) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: update non-existent documents", %{ coll_name: coll_name, conn: conn, @@ -145,7 +145,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.import_documents(coll_name, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: multi-search with no documents", %{conn: conn, map_conn: map_conn} do body = %{ @@ -170,7 +170,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.multi_search(body, List.flatten([conn: map_conn], params)) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: update documents by query", %{ coll_name: coll_name, conn: conn, @@ -228,7 +228,7 @@ defmodule DocumentsTest do ) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: importing empty documents", %{coll_name: coll_name} do assert {:ok, ""} = Documents.import_documents(coll_name, []) @@ -239,8 +239,8 @@ defmodule DocumentsTest do Documents.import_documents(coll_name, [%{}]) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] - test "success: import documents where payload is type of string", %{coll_name: coll_name} do + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] + test "success: import documents where payload is JSONL", %{coll_name: coll_name} do body = [ %{ @@ -275,6 +275,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.import_documents(coll_name, body) end + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: import documents", %{coll_name: coll_name} do body = [ @@ -309,7 +310,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.import_documents(coll_name, body, action: "create") end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: index a document", %{coll_name: coll_name, conn: conn, map_conn: map_conn} do shoes_id = 220 @@ -333,7 +334,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.index_document(coll_name, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list collection overrides", %{ coll_name: coll_name, conn: conn, @@ -352,7 +353,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.get_search_overrides("xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: get a non-existent override", %{ coll_name: coll_name, conn: conn, @@ -366,7 +367,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.get_search_override(coll_name, "xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: delete a non-existent override", %{ coll_name: coll_name, conn: conn, @@ -380,7 +381,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.delete_search_override(coll_name, "xyz", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete a document", %{coll_name: coll_name, conn: conn, map_conn: map_conn} do shoes_id = 420 @@ -412,7 +413,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.delete_document(coll_name, id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete all documents", %{coll_name: coll_name, conn: conn, map_conn: map_conn} do body = [ @@ -456,7 +457,7 @@ defmodule DocumentsTest do assert {:ok, _} = Documents.delete_documents(coll_name, List.flatten([conn: map_conn], opts)) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: get a non-existent document", %{ coll_name: coll_name, conn: conn, @@ -473,7 +474,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.get_document(coll_name, document_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: export document from a non-existent collection", %{conn: conn, map_conn: map_conn} do opts = [exclude_fields: "fields"] @@ -487,7 +488,7 @@ defmodule DocumentsTest do assert {:error, _} = Documents.export_documents("xyz", List.flatten([conn: map_conn], opts)) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: upsert a search override", %{ coll_name: coll_name, conn: conn, @@ -520,7 +521,7 @@ defmodule DocumentsTest do Documents.upsert_search_override(coll_name, "customize-apple", body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "field" do assert [num_deleted: :integer] = Documents.__fields__(:delete_documents_200_json_resp) assert [num_updated: :integer] = Documents.__fields__(:update_documents_200_json_resp) diff --git a/test/operations/health_test.exs b/test/operations/health_test.exs index 00a8d99..b9ef9f4 100644 --- a/test/operations/health_test.exs +++ b/test/operations/health_test.exs @@ -12,7 +12,7 @@ defmodule HealthTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: health check", %{conn: conn, map_conn: map_conn} do assert {:ok, %HealthStatus{ok: true}} = Health.health() assert {:ok, %HealthStatus{ok: true}} = Health.health([]) @@ -20,7 +20,7 @@ defmodule HealthTest do assert {:ok, %HealthStatus{ok: true}} = Health.health(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: health check timeout" do conn = Connection.new(%{ @@ -33,7 +33,7 @@ defmodule HealthTest do assert {:error, "timeout"} = Health.health(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: health check connection refused" do conn = Connection.new(%{ @@ -46,7 +46,7 @@ defmodule HealthTest do assert {:error, "connection refused"} = Health.health(conn: conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "error: health check non-existing domain" do conn = %{ api_key: "wrong_key", diff --git a/test/operations/join_test.exs b/test/operations/join_test.exs index 543bceb..ad2fdd1 100644 --- a/test/operations/join_test.exs +++ b/test/operations/join_test.exs @@ -346,7 +346,7 @@ defmodule JoinTest do :ok end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: one-to-one relation" do searches = %{ searches: [ @@ -379,7 +379,7 @@ defmodule JoinTest do }} = Documents.multi_search(searches) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: one-to-many relation (simple)" do searches = %{ searches: [ @@ -437,7 +437,7 @@ defmodule JoinTest do }} = Documents.multi_search(searches) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: one-to-many relation (specialized)" do searches = %{ searches: [ @@ -474,7 +474,7 @@ defmodule JoinTest do }} = Documents.multi_search(searches) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: merging or nesting joined fields" do searches = %{ searches: [ @@ -515,7 +515,7 @@ defmodule JoinTest do }} = Documents.multi_search(searches) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: forcing nested array for joined fields" do searches = %{ searches: [ @@ -553,7 +553,7 @@ defmodule JoinTest do }} = Documents.multi_search(searches) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: left join" do opts = [ collection: "authors", @@ -578,7 +578,7 @@ defmodule JoinTest do }} = Documents.search_collection("authors", opts) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: nested joins" do opts = [ q: "shampoo", @@ -635,7 +635,7 @@ defmodule JoinTest do }} = Documents.search_collection("join_products", opts) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: nested joins (geo radius)" do opts = [ q: "shampoo", diff --git a/test/operations/keys_test.exs b/test/operations/keys_test.exs index 1857d02..f28ecb0 100644 --- a/test/operations/keys_test.exs +++ b/test/operations/keys_test.exs @@ -29,7 +29,7 @@ defmodule KeysTest do %{api_key_schema: api_key_schema, conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: get a specific key", %{ api_key_schema: api_key_schema, conn: conn, @@ -45,7 +45,7 @@ defmodule KeysTest do assert {:ok, %ApiKey{id: ^key_id}} = Keys.get_key(key_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list API keys", %{conn: conn, map_conn: map_conn} do assert {:ok, %ApiKeysResponse{keys: keys}} = Keys.get_keys() assert length(keys) >= 0 @@ -55,7 +55,7 @@ defmodule KeysTest do assert {:ok, %ApiKeysResponse{}} = Keys.get_keys(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete an API key", %{ api_key_schema: api_key_schema, conn: conn, @@ -71,7 +71,7 @@ defmodule KeysTest do assert {:error, _} = Keys.delete_key(key_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: create an search-only API key", %{ api_key_schema: api_key_schema, conn: conn, @@ -83,7 +83,7 @@ defmodule KeysTest do assert {:ok, %ApiKey{}} = Keys.create_key(api_key_schema, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: create an admin API key", %{api_key_schema: api_key_schema} do body = api_key_schema diff --git a/test/operations/nl_search_models_test.exs b/test/operations/nl_search_models_test.exs new file mode 100644 index 0000000..8057a8a --- /dev/null +++ b/test/operations/nl_search_models_test.exs @@ -0,0 +1,23 @@ +defmodule NlSearchModelsTest do + use ExUnit.Case, async: true + + # alias OpenApiTypesense.Connection + # alias OpenApiTypesense.NlSearchModels + + setup_all do + # conn = Connection.new() + # map_conn = %{api_key: "xyz", host: "localhost", port: 8108, scheme: "http"} + + # on_exit(fn -> + # end) + + # %{conn: conn, map_conn: map_conn} + :ok + end + + @tag [nls: true] + # test "success: get a specific key", %{conn: conn, map_conn: map_conn} do + test "success: get a specific key" do + assert 1 === false + end +end diff --git a/test/operations/operations_test.exs b/test/operations/operations_test.exs index 9715918..05d35bf 100644 --- a/test/operations/operations_test.exs +++ b/test/operations/operations_test.exs @@ -15,7 +15,7 @@ defmodule OperationsTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: retrieve api stats", %{conn: conn, map_conn: map_conn} do assert {:ok, %APIStatsResponse{}} = Operations.retrieve_api_stats() assert {:ok, %APIStatsResponse{}} = Operations.retrieve_api_stats([]) @@ -23,7 +23,7 @@ defmodule OperationsTest do assert {:ok, %APIStatsResponse{}} = Operations.retrieve_api_stats(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: retrieve metrics", %{conn: conn, map_conn: map_conn} do assert {:ok, %{system_cpu_active_percentage: _}} = Operations.retrieve_metrics() assert {:ok, %{system_cpu_active_percentage: _}} = Operations.retrieve_metrics([]) @@ -31,18 +31,22 @@ defmodule OperationsTest do assert {:ok, %{system_cpu_active_percentage: _}} = Operations.retrieve_metrics(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: toggle threshold time for request log", %{conn: conn, map_conn: map_conn} do assert {:ok, %SuccessStatus{success: true}} = - Operations.config(%{"log_slow_requests_time_ms" => 2_000}) + Operations.toggle_slow_request_log(%{"log-slow-requests-time-ms" => 2_000}) - body = %{"log_slow_requests_time_ms" => -1} - assert {:ok, %SuccessStatus{success: true}} = Operations.config(body, []) - assert {:ok, %SuccessStatus{success: true}} = Operations.config(body, conn: conn) - assert {:ok, %SuccessStatus{success: true}} = Operations.config(body, conn: map_conn) + body = %{"log-slow-requests-time-ms" => -1} + assert {:ok, %SuccessStatus{success: true}} = Operations.toggle_slow_request_log(body, []) + + assert {:ok, %SuccessStatus{success: true}} = + Operations.toggle_slow_request_log(body, conn: conn) + + assert {:ok, %SuccessStatus{success: true}} = + Operations.toggle_slow_request_log(body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: clear cache", %{conn: conn, map_conn: map_conn} do assert {:ok, %SuccessStatus{success: true}} = Operations.clear_cache() assert {:ok, %SuccessStatus{success: true}} = Operations.clear_cache([]) @@ -50,15 +54,15 @@ defmodule OperationsTest do assert {:ok, %SuccessStatus{success: true}} = Operations.clear_cache(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: compact database", %{conn: conn, map_conn: map_conn} do - assert {:ok, %SuccessStatus{success: true}} = Operations.compact() - assert {:ok, %SuccessStatus{success: true}} = Operations.compact([]) - assert {:ok, %SuccessStatus{success: true}} = Operations.compact(conn: conn) - assert {:ok, %SuccessStatus{success: true}} = Operations.compact(conn: map_conn) + assert {:ok, %SuccessStatus{success: true}} = Operations.compact_db() + assert {:ok, %SuccessStatus{success: true}} = Operations.compact_db([]) + assert {:ok, %SuccessStatus{success: true}} = Operations.compact_db(conn: conn) + assert {:ok, %SuccessStatus{success: true}} = Operations.compact_db(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: take snapshot", %{conn: conn, map_conn: map_conn} do # we have to add sleep timer for github actions # otherwise it will return like: @@ -82,7 +86,7 @@ defmodule OperationsTest do Operations.take_snapshot(List.flatten([conn: map_conn], params)) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: re-elect leader", %{conn: conn, map_conn: map_conn} do assert {:ok, %SuccessStatus{success: false}} = Operations.vote() assert {:ok, %SuccessStatus{success: false}} = Operations.vote([]) @@ -90,7 +94,7 @@ defmodule OperationsTest do assert {:ok, %SuccessStatus{success: false}} = Operations.vote(conn: map_conn) end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: get schema changes", %{conn: conn, map_conn: map_conn} do assert {:ok, schemas} = Operations.get_schema_changes() assert length(schemas) >= 0 diff --git a/test/operations/override_test.exs b/test/operations/override_test.exs index ab0f91a..3b61b4e 100644 --- a/test/operations/override_test.exs +++ b/test/operations/override_test.exs @@ -21,4 +21,14 @@ defmodule OverrideTest do assert {:error, _} = Override.get_search_override("helmets", "custom-helmet", conn: conn) assert {:error, _} = Override.get_search_override("helmets", "custom-helmet", conn: map_conn) end + + @tag ["29.0": true] + test "error: retrieve an override (> v28.0)", %{conn: conn, map_conn: map_conn} do + assert {:error, %ApiResponse{message: "Collection not found"}} = + Override.get_search_override("helmets", "custom-helmet") + + assert {:error, _} = Override.get_search_override("helmets", "custom-helmet", []) + assert {:error, _} = Override.get_search_override("helmets", "custom-helmet", conn: conn) + assert {:error, _} = Override.get_search_override("helmets", "custom-helmet", conn: map_conn) + end end diff --git a/test/operations/presets_test.exs b/test/operations/presets_test.exs index ea8aa0e..964fa15 100644 --- a/test/operations/presets_test.exs +++ b/test/operations/presets_test.exs @@ -33,7 +33,7 @@ defmodule PresetsTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list presets", %{conn: conn, map_conn: map_conn} do assert {:ok, %PresetsRetrieveSchema{presets: presets}} = Presets.retrieve_all_presets() assert length(presets) >= 1 @@ -43,7 +43,7 @@ defmodule PresetsTest do assert {:ok, _} = Presets.retrieve_all_presets(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: get a preset", %{conn: conn, map_conn: map_conn} do assert {:error, %ApiResponse{message: "Not found."}} = Presets.retrieve_preset("listing_view") assert {:error, _} = Presets.retrieve_preset("listing_view", []) @@ -51,7 +51,7 @@ defmodule PresetsTest do assert {:error, _} = Presets.retrieve_preset("listing_view", conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: upsert a preset", %{conn: conn, map_conn: map_conn} do body = %{ @@ -70,7 +70,7 @@ defmodule PresetsTest do assert {:ok, _} = Presets.upsert_preset("restaurant_view", body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete a preset", %{conn: conn, map_conn: map_conn} do body = %{ diff --git a/test/operations/stemming_test.exs b/test/operations/stemming_test.exs index 20f9cf3..fbd2051 100644 --- a/test/operations/stemming_test.exs +++ b/test/operations/stemming_test.exs @@ -32,7 +32,7 @@ defmodule StemmingTest do %{id: id, conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": false, "27.0": false, "26.0": false] test "success: create stemming dictionaries", %{conn: conn, map_conn: map_conn} do id = "example-stemming" @@ -64,7 +64,7 @@ defmodule StemmingTest do ]} = Stemming.import_stemming_dictionary(body, id: id, conn: map_conn) end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": false, "27.0": false, "26.0": false] test "success: list stemming dictionaries", %{conn: conn, map_conn: map_conn} do assert {:ok, %Stemming{}} = Stemming.list_stemming_dictionaries() assert {:ok, %Stemming{}} = Stemming.list_stemming_dictionaries([]) @@ -72,13 +72,13 @@ defmodule StemmingTest do assert {:ok, %Stemming{}} = Stemming.list_stemming_dictionaries(conn: map_conn) end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": false, "27.0": false, "26.0": false] test "error: non-existent stemming dictionary" do - assert {:error, %ApiResponse{message: "Not Found"}} = + assert {:error, %ApiResponse{message: "Collection not found"}} = Stemming.get_stemming_dictionary("non-existent") end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": false, "27.0": false, "26.0": false] test "success: get specific stemming dictionary", %{id: id, conn: conn, map_conn: map_conn} do body = [ %{"word" => "mice", "root" => "mouse"}, @@ -101,7 +101,7 @@ defmodule StemmingTest do Stemming.get_stemming_dictionary(id, conn: map_conn) end - @tag ["28.0": true, "27.1": false, "27.0": false, "26.0": false] + @tag ["29.0": true, "28.0": true, "27.1": false, "27.0": false, "26.0": false] test "field" do assert [dictionaries: [string: :generic]] = Stemming.__fields__(:list_stemming_dictionaries_200_json_resp) diff --git a/test/operations/stopwords_test.exs b/test/operations/stopwords_test.exs index 4114cf7..8026c27 100644 --- a/test/operations/stopwords_test.exs +++ b/test/operations/stopwords_test.exs @@ -24,7 +24,7 @@ defmodule StopwordsTest do %{conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list stopwords sets", %{conn: conn, map_conn: map_conn} do assert {:ok, %StopwordsSetsRetrieveAllSchema{stopwords: stopwords}} = Stopwords.retrieve_stopwords_sets() @@ -35,7 +35,7 @@ defmodule StopwordsTest do assert {:ok, _} = Stopwords.retrieve_stopwords_sets(conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: add stopwords", %{conn: conn, map_conn: map_conn} do set_id = "stopword_set_countries" @@ -51,7 +51,7 @@ defmodule StopwordsTest do assert {:ok, _} = Stopwords.upsert_stopwords_set(set_id, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: retrieve specific stopwords set", %{conn: conn, map_conn: map_conn} do set_id = "stopword_set_names" @@ -71,7 +71,7 @@ defmodule StopwordsTest do assert {:ok, _} = Stopwords.retrieve_stopwords_set(set_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete specific stopwords set", %{conn: conn, map_conn: map_conn} do set_id = "stopword_set_companies" @@ -88,7 +88,7 @@ defmodule StopwordsTest do assert {:error, _} = Stopwords.delete_stopwords_set(set_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "field" do assert [id: {:string, :generic}] = Stopwords.__fields__(:delete_stopwords_set_200_json_resp) end diff --git a/test/operations/synonyms_test.exs b/test/operations/synonyms_test.exs index 8d519ac..9dc7459 100644 --- a/test/operations/synonyms_test.exs +++ b/test/operations/synonyms_test.exs @@ -32,7 +32,7 @@ defmodule SynonymsTest do %{coll_name: collection_name, conn: conn, map_conn: map_conn} end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: list collection synonyms", %{ coll_name: coll_name, conn: conn, @@ -48,7 +48,7 @@ defmodule SynonymsTest do assert {:ok, _} = Synonyms.get_search_synonyms(coll_name, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: upsert a collection synonym", %{ coll_name: coll_name, conn: conn, @@ -70,7 +70,7 @@ defmodule SynonymsTest do assert {:ok, _} = Synonyms.upsert_search_synonym(coll_name, synonym_id, body, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: delete a collection synonym", %{ coll_name: coll_name, conn: conn, @@ -93,7 +93,7 @@ defmodule SynonymsTest do assert {:error, _} = Synonyms.delete_search_synonym(coll_name, synonym_id, conn: map_conn) end - @tag ["28.0": true, "27.1": true, "27.0": true, "26.0": true] + @tag ["29.0": true, "28.0": true, "27.1": true, "27.0": true, "26.0": true] test "success: get a collection synonym", %{ coll_name: coll_name, conn: conn,