diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 Bloodhound 
 ![compatbuild](https://github.com/bitemyapp/bloodhound/actions/workflows/compat.yml/badge.svg)
-![haskell-ci](https://github.com/bitemyapp/bloodhound/actions/workflows/haskell-ci.yml/badge.svg)
+[![Haskell](https://github.com/bitemyapp/bloodhound/actions/workflows/haskell.yml/badge.svg)](https://github.com/bitemyapp/bloodhound/actions/workflows/haskell.yml)
 ![nix](https://github.com/bitemyapp/bloodhound/actions/workflows/nix.yml/badge.svg)
 ![ormolu](https://github.com/bitemyapp/bloodhound/actions/workflows/ormolu.yml/badge.svg)
 [![Hackage](https://img.shields.io/hackage/v/bloodhound.svg?style=flat)](https://hackage.haskell.org/package/bloodhound)
diff --git a/bloodhound.cabal b/bloodhound.cabal
--- a/bloodhound.cabal
+++ b/bloodhound.cabal
@@ -1,14 +1,14 @@
 cabal-version:  3.4
 
 name:           bloodhound
-version:        0.23.0.1
+version:        0.24.0.0
 synopsis:       Elasticsearch client library for Haskell
 description:    Elasticsearch made awesome for Haskell hackers
 category:       Database, Search
 homepage:       https://github.com/bitemyapp/bloodhound.git#readme
 bug-reports:    https://github.com/bitemyapp/bloodhound.git/issues
 author:         Chris Allen
-maintainer:     gautier.difolco@gmail.com
+maintainer:     foss@difolco.dev
 copyright:      2018 Chris Allen
 license:        BSD-3-Clause
 license-file:   LICENSE
@@ -33,6 +33,7 @@
       Database.Bloodhound.Common.Client
       Database.Bloodhound.Common.Requests
       Database.Bloodhound.Common.Types
+      Database.Bloodhound.Dynamic.Client
       Database.Bloodhound.ElasticSearch7.Client
       Database.Bloodhound.ElasticSearch7.Requests
       Database.Bloodhound.ElasticSearch7.Types
@@ -96,6 +97,7 @@
     , hashable >=1 && <2
     , http-client >=0.4.30 && <1
     , http-types >=0.8 && <1
+    , microlens >=0.4
     , mtl >=1.0 && <3
     , network-uri >=2.6 && <3
     , optics-core >=0.4 && <0.5
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,11 @@
+0.24.0.0
+========
+- @blackheaven
+  - fix: remove `putMapping` deprecation
+  - strong type backend
+  - add dynamic backend operations
+  - complete/rename (uniformize) `optics` definitions
+
 0.23.0.1
 ========
 - @arybczak
diff --git a/src/Database/Bloodhound/Client/Cluster.hs b/src/Database/Bloodhound/Client/Cluster.hs
--- a/src/Database/Bloodhound/Client/Cluster.hs
+++ b/src/Database/Bloodhound/Client/Cluster.hs
@@ -1,6 +1,11 @@
+{-# LANGUAGE ConstraintKinds #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 
 module Database.Bloodhound.Client.Cluster
@@ -8,17 +13,25 @@
     BH (..),
     BHEnv (..),
     MonadBH (..),
+    BackendType (..),
+    WithBackend,
+    WithBackendType,
+    StaticBH (..),
+    SBackendType (..),
     emptyBody,
     mkBHEnv,
     performBHRequest,
     runBH,
     tryPerformBHRequest,
+    unsafePerformBH,
+    withDynamicBH,
   )
 where
 
 import Control.Monad.Catch
 import Control.Monad.Except
 import qualified Data.ByteString.Lazy.Char8 as L
+import Data.Kind
 import qualified Data.Text as T
 import Database.Bloodhound.Internal.Client.BHRequest
 import Database.Bloodhound.Internal.Utils.Imports
@@ -28,16 +41,16 @@
 import Database.Bloodhound.Internal.Versions.Common.Types.Nodes as ReexportCompat
 import Database.Bloodhound.Internal.Versions.Common.Types.Snapshots as ReexportCompat
 import Database.Bloodhound.Internal.Versions.Common.Types.Units as ReexportCompat
-import Network.HTTP.Client
+import qualified Network.HTTP.Client as HTTP
 import qualified Network.URI as URI
 
 -- | Common environment for Elasticsearch calls. Connections will be
 --   pipelined according to the provided HTTP connection manager.
 data BHEnv = BHEnv
   { bhServer :: Server,
-    bhManager :: Manager,
+    bhManager :: HTTP.Manager,
     -- | Low-level hook that is run before every request is sent. Used to implement custom authentication strategies. Defaults to 'return' with 'mkBHEnv'.
-    bhRequestHook :: Request -> IO Request
+    bhRequestHook :: HTTP.Request -> IO HTTP.Request
   }
 
 -- | All API calls to Elasticsearch operate within
@@ -46,18 +59,36 @@
 --   own monad transformer stack. A default instance for a ReaderT and
 --   alias 'BH' is provided for the simple case.
 class (Functor m, Applicative m, MonadIO m, MonadCatch m) => MonadBH m where
+  type Backend m :: BackendType
   dispatch :: BHRequest contextualized body -> m (BHResponse contextualized body)
   tryEsError :: m a -> m (Either EsError a)
   throwEsError :: EsError -> m a
 
+-- | Backend (i.e. implementation) the queries are ran against
+data BackendType
+  = ElasticSearch7
+  | OpenSearch1
+  | OpenSearch2
+  | -- | unknown, can be anything
+    Dynamic
+
+-- | Best-effort, by-passed for 'Dynamic', statically enforced implementation
+type family WithBackendType (expected :: BackendType) (actual :: BackendType) :: Constraint where
+  WithBackendType e 'Dynamic = ()
+  WithBackendType e a = e ~ a
+
+-- | Helper for 'WithBackendType'
+type WithBackend (backend :: BackendType) (m :: Type -> Type) = WithBackendType backend (Backend m)
+
 -- | Create a 'BHEnv' with all optional fields defaulted. HTTP hook
 -- will be a noop. You can use the exported fields to customize
 -- it further, e.g.:
 --
 -- >> (mkBHEnv myServer myManager) { bhRequestHook = customHook }
-mkBHEnv :: Server -> Manager -> BHEnv
+mkBHEnv :: Server -> HTTP.Manager -> BHEnv
 mkBHEnv s m = BHEnv s m return
 
+-- | Basic BH implementation
 newtype BH m a = BH
   { unBH :: ReaderT BHEnv (ExceptT EsError m) a
   }
@@ -87,27 +118,26 @@
       local f (m r)
 
 instance (Functor m, Applicative m, MonadIO m, MonadCatch m, MonadThrow m) => MonadBH (BH m) where
+  type Backend (BH m) = 'Dynamic
   dispatch request = BH $ do
     env <- ask @BHEnv
     let url = getEndpoint (bhServer env) (bhRequestEndpoint request)
     initReq <- liftIO $ parseUrl' url
     let reqHook = bhRequestHook env
-    let reqBody = RequestBodyLBS $ fromMaybe emptyBody $ bhRequestBody request
+    let reqBody = HTTP.RequestBodyLBS $ fromMaybe emptyBody $ bhRequestBody request
     req <-
       liftIO $
         reqHook $
-          setRequestIgnoreStatus $
+          HTTP.setRequestIgnoreStatus $
             initReq
-              { method = bhRequestMethod request,
-                requestHeaders =
-                  -- "application/x-ndjson" for bulk
-                  ("Content-Type", "application/json") : requestHeaders initReq,
-                requestBody = reqBody
+              { HTTP.method = bhRequestMethod request,
+                HTTP.requestHeaders =
+                  ("Content-Type", "application/json") : HTTP.requestHeaders initReq,
+                HTTP.requestBody = reqBody
               }
-    -- req <- liftIO $ reqHook $ setRequestIgnoreStatus $ initReq { method = dMethod
-    --                                                            , requestBody = reqBody }
+
     let mgr = bhManager env
-    BHResponse <$> liftIO (httpLbs req mgr)
+    BHResponse <$> liftIO (HTTP.httpLbs req mgr)
   tryEsError = try
   throwEsError = throwM
 
@@ -126,8 +156,62 @@
 emptyBody :: L.ByteString
 emptyBody = L.pack ""
 
-parseUrl' :: (MonadThrow m) => Text -> m Request
-parseUrl' t = parseRequest (URI.escapeURIString URI.isAllowedInURI (T.unpack t))
+parseUrl' :: (MonadThrow m) => Text -> m HTTP.Request
+parseUrl' t = HTTP.parseRequest (URI.escapeURIString URI.isAllowedInURI (T.unpack t))
 
 runBH :: BHEnv -> BH m a -> m (Either EsError a)
 runBH e f = runExceptT $ runReaderT (unBH f) e
+
+-- | Statically-type backend.
+--
+-- It's also an useful wrapper for 'DerivingVia'
+newtype StaticBH (backend :: BackendType) m a = StaticBH
+  {runStaticBH :: m a}
+  deriving newtype
+    ( Functor,
+      Applicative,
+      Monad,
+      MonadIO,
+      MonadReader r,
+      MonadState s,
+      MonadWriter w,
+      Alternative,
+      MonadPlus,
+      MonadFix,
+      MonadThrow,
+      MonadCatch,
+      MonadFail,
+      MonadMask
+    )
+
+instance MonadTrans (StaticBH backend) where
+  lift = StaticBH
+
+instance (MonadBH m) => MonadBH (StaticBH backend m) where
+  type Backend (StaticBH backend m) = backend
+  dispatch = StaticBH . dispatch
+  tryEsError = StaticBH . tryEsError . runStaticBH
+  throwEsError = StaticBH . throwEsError
+
+-- | Run a piece of code as-if we are on a given backend
+unsafePerformBH :: StaticBH backend m a -> m a
+unsafePerformBH = runStaticBH
+
+-- | Dependently-typed version of 'BackendType'
+data SBackendType :: BackendType -> Type where
+  SElasticSearch7 :: SBackendType 'ElasticSearch7
+  SOpenSearch1 :: SBackendType 'OpenSearch1
+  SOpenSearch2 :: SBackendType 'OpenSearch2
+
+-- | Run an action given an actual backend
+withDynamicBH ::
+  (MonadBH m) =>
+  BackendType ->
+  (forall backend. SBackendType backend -> StaticBH backend m a) ->
+  m a
+withDynamicBH backend f =
+  case backend of
+    ElasticSearch7 -> unsafePerformBH $ f SElasticSearch7
+    OpenSearch1 -> unsafePerformBH $ f SOpenSearch1
+    OpenSearch2 -> unsafePerformBH $ f SOpenSearch2
+    Dynamic -> throwEsError $ EsError Nothing "Cannot perform on a 'Dynamic' backend"
diff --git a/src/Database/Bloodhound/Common/Client.hs b/src/Database/Bloodhound/Common/Client.hs
--- a/src/Database/Bloodhound/Common/Client.hs
+++ b/src/Database/Bloodhound/Common/Client.hs
@@ -462,7 +462,6 @@
 -- Response {responseStatus = Status {statusCode = 200, statusMessage = "OK"}, responseVersion = HTTP/1.1, responseHeaders = [("content-type","application/json; charset=UTF-8"),("content-encoding","gzip"),("transfer-encoding","chunked")], responseBody = "{\"acknowledged\":true}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}
 putMapping :: forall r a m. (MonadBH m, FromJSON r, ToJSON a) => IndexName -> a -> m r
 putMapping indexName mapping = performBHRequest $ Requests.putMapping indexName mapping
-{-# DEPRECATED putMapping "See <https://www.elastic.co/guide/en/elasticsearch/reference/7.17/removal-of-types.html>" #-}
 
 -- | 'indexDocument' is the primary way to save a single document in
 --  Elasticsearch. The document itself is simply something we can
diff --git a/src/Database/Bloodhound/Common/Requests.hs b/src/Database/Bloodhound/Common/Requests.hs
--- a/src/Database/Bloodhound/Common/Requests.hs
+++ b/src/Database/Bloodhound/Common/Requests.hs
@@ -505,60 +505,6 @@
     endpoint = ["_cluster", "health", unIndexName indexName] `withQueries` params
     params = [("wait_for_status", Just "yellow"), ("timeout", Just "10s")]
 
-data HealthStatus = HealthStatus
-  { healthStatusClusterName :: Text,
-    healthStatusStatus :: Text,
-    healthStatusTimedOut :: Bool,
-    healthStatusNumberOfNodes :: Int,
-    healthStatusNumberOfDataNodes :: Int,
-    healthStatusActivePrimaryShards :: Int,
-    healthStatusActiveShards :: Int,
-    healthStatusRelocatingShards :: Int,
-    healthStatusInitializingShards :: Int,
-    healthStatusUnassignedShards :: Int,
-    healthStatusDelayedUnassignedShards :: Int,
-    healthStatusNumberOfPendingTasks :: Int,
-    healthStatusNumberOfInFlightFetch :: Int,
-    healthStatusTaskMaxWaitingInQueueMillis :: Int,
-    healthStatusActiveShardsPercentAsNumber :: Float
-  }
-  deriving stock (Eq, Show)
-
-instance FromJSON HealthStatus where
-  parseJSON =
-    withObject "HealthStatus" $ \v ->
-      HealthStatus
-        <$> v
-          .: "cluster_name"
-        <*> v
-          .: "status"
-        <*> v
-          .: "timed_out"
-        <*> v
-          .: "number_of_nodes"
-        <*> v
-          .: "number_of_data_nodes"
-        <*> v
-          .: "active_primary_shards"
-        <*> v
-          .: "active_shards"
-        <*> v
-          .: "relocating_shards"
-        <*> v
-          .: "initializing_shards"
-        <*> v
-          .: "unassigned_shards"
-        <*> v
-          .: "delayed_unassigned_shards"
-        <*> v
-          .: "number_of_pending_tasks"
-        <*> v
-          .: "number_of_in_flight_fetch"
-        <*> v
-          .: "task_max_waiting_in_queue_millis"
-        <*> v
-          .: "active_shards_percent_as_number"
-
 openOrCloseIndexes :: OpenCloseIndex -> IndexName -> BHRequest StatusIndependant Acknowledged
 openOrCloseIndexes oci indexName =
   post [unIndexName indexName, stringifyOCIndex] emptyBody
@@ -722,41 +668,6 @@
     endpoint = [unIndexName indexName, "_doc", docId] `withQueries` indexQueryString cfg (DocId docId)
     body = encodeDocument cfg document
 
-data IndexedDocument = IndexedDocument
-  { idxDocIndex :: Text,
-    idxDocType :: Maybe Text,
-    idxDocId :: Text,
-    idxDocVersion :: Int,
-    idxDocResult :: Text,
-    idxDocShards :: ShardResult,
-    idxDocSeqNo :: Int,
-    idxDocPrimaryTerm :: Int
-  }
-  deriving stock (Eq, Show)
-
-{-# DEPRECATED idxDocType "deprecated since ElasticSearch 6.0" #-}
-
-instance FromJSON IndexedDocument where
-  parseJSON =
-    withObject "IndexedDocument" $ \v ->
-      IndexedDocument
-        <$> v
-          .: "_index"
-        <*> v
-          .:? "_type"
-        <*> v
-          .: "_id"
-        <*> v
-          .: "_version"
-        <*> v
-          .: "result"
-        <*> v
-          .: "_shards"
-        <*> v
-          .: "_seq_no"
-        <*> v
-          .: "_primary_term"
-
 -- | 'updateDocument' provides a way to perform an partial update of a
 -- an already indexed document.
 updateDocument ::
@@ -839,66 +750,6 @@
   post [unIndexName indexName, "_delete_by_query"] (encode body)
   where
     body = object ["query" .= query]
-
-data DeletedDocuments = DeletedDocuments
-  { delDocsTook :: Int,
-    delDocsTimedOut :: Bool,
-    delDocsTotal :: Int,
-    delDocsDeleted :: Int,
-    delDocsBatches :: Int,
-    delDocsVersionConflicts :: Int,
-    delDocsNoops :: Int,
-    delDocsRetries :: DeletedDocumentsRetries,
-    delDocsThrottledMillis :: Int,
-    delDocsRequestsPerSecond :: Float,
-    delDocsThrottledUntilMillis :: Int,
-    delDocsFailures :: [Value] -- TODO find examples
-  }
-  deriving stock (Eq, Show)
-
-instance FromJSON DeletedDocuments where
-  parseJSON =
-    withObject "DeletedDocuments" $ \v ->
-      DeletedDocuments
-        <$> v
-          .: "took"
-        <*> v
-          .: "timed_out"
-        <*> v
-          .: "total"
-        <*> v
-          .: "deleted"
-        <*> v
-          .: "batches"
-        <*> v
-          .: "version_conflicts"
-        <*> v
-          .: "noops"
-        <*> v
-          .: "retries"
-        <*> v
-          .: "throttled_millis"
-        <*> v
-          .: "requests_per_second"
-        <*> v
-          .: "throttled_until_millis"
-        <*> v
-          .: "failures"
-
-data DeletedDocumentsRetries = DeletedDocumentsRetries
-  { delDocsRetriesBulk :: Int,
-    delDocsRetriesSearch :: Int
-  }
-  deriving stock (Eq, Show)
-
-instance FromJSON DeletedDocumentsRetries where
-  parseJSON =
-    withObject "DeletedDocumentsRetries" $ \v ->
-      DeletedDocumentsRetries
-        <$> v
-          .: "bulk"
-        <*> v
-          .: "search"
 
 -- | 'bulk' uses
 --   <http://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html Elasticsearch's bulk API>
diff --git a/src/Database/Bloodhound/Dynamic/Client.hs b/src/Database/Bloodhound/Dynamic/Client.hs
new file mode 100644
--- /dev/null
+++ b/src/Database/Bloodhound/Dynamic/Client.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+-- |
+-- Module : Database.Bloodhound.Dynamic.Client
+-- Copyright : (C) 2014, 2018 Chris Allen
+-- License : BSD-style (see the file LICENSE)
+-- Maintainer : Chris Allen <cma@bitemyapp.com>
+-- Stability : provisional
+-- Portability : GHC
+--
+-- Dynamically route the query depending on the backend.
+--
+-- @
+-- withFetchedBackendType $ \backend ->
+--   pitSearch backend index search
+-- @
+module Database.Bloodhound.Dynamic.Client
+  ( module Reexport,
+    guessBackendType,
+    withFetchedBackendType,
+    pitSearch,
+  )
+where
+
+import Data.Aeson
+import Data.Maybe (fromMaybe, listToMaybe)
+import qualified Data.Versions as Versions
+import Database.Bloodhound.Client.Cluster
+import Database.Bloodhound.Common.Client as Reexport
+import qualified Database.Bloodhound.ElasticSearch7.Client as ClientES2
+import qualified Database.Bloodhound.OpenSearch2.Client as ClientOS2
+import Database.Bloodhound.OpenSearch2.Types
+import Lens.Micro (toListOf)
+import Prelude hiding (filter, head)
+
+-- | Try to guess the current 'BackendType'
+guessBackendType :: NodeInfo -> Maybe BackendType
+guessBackendType nodeInfo =
+  case listToMaybe $ toListOf Versions.major $ versionNumber $ nodeInfoESVersion nodeInfo of
+    Just 7 -> Just ElasticSearch7
+    Just 1 -> Just OpenSearch1
+    Just 2 -> Just OpenSearch2
+    _ -> Nothing
+
+-- | Fetch the currently running backend and run backend-dependent code
+withFetchedBackendType :: (MonadBH m) => (forall backend. SBackendType backend -> m a) -> m a
+withFetchedBackendType f = do
+  nodeInfo <- getNodesInfo LocalNode
+  let backend = fromMaybe Dynamic $ listToMaybe (nodesInfo nodeInfo) >>= guessBackendType
+  withDynamicBH backend $ StaticBH . f
+
+-- | 'pitSearch' uses the point in time (PIT) API of elastic, for a given
+-- 'IndexName'. Requires Elasticsearch >=7.10 or OpenSearch >=2. Note that this will consume the
+-- entire search result set and will be doing O(n) list appends so this may
+-- not be suitable for large result sets. In that case, the point in time API
+-- should be used directly with `openPointInTime` and `closePointInTime`.
+--
+-- Note that 'pitSearch' utilizes the 'search_after' parameter under the hood,
+-- which requires a non-empty 'sortBody' field in the provided 'Search' value.
+-- Otherwise, 'pitSearch' will fail to return all matching documents.
+--
+-- For more information see
+-- <https://opensearch.org/docs/latest/search-plugins/point-in-time/>.
+pitSearch ::
+  forall a m backend.
+  (FromJSON a, MonadBH m) =>
+  SBackendType backend ->
+  IndexName ->
+  Search ->
+  m [Hit a]
+pitSearch backend indexName search =
+  case backend of
+    SElasticSearch7 -> unsafePerformBH @'ElasticSearch7 $ ClientES2.pitSearch indexName search
+    SOpenSearch1 -> throwEsError $ EsError Nothing "pitSearch is not supported by OpenSearch1"
+    SOpenSearch2 -> unsafePerformBH @'OpenSearch2 $ ClientOS2.pitSearch indexName search
diff --git a/src/Database/Bloodhound/ElasticSearch7/Client.hs b/src/Database/Bloodhound/ElasticSearch7/Client.hs
--- a/src/Database/Bloodhound/ElasticSearch7/Client.hs
+++ b/src/Database/Bloodhound/ElasticSearch7/Client.hs
@@ -32,7 +32,12 @@
 --
 -- For more information see
 -- <https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html>.
-pitSearch :: forall a m. (FromJSON a, MonadBH m) => IndexName -> Search -> m [Hit a]
+pitSearch ::
+  forall a m.
+  (FromJSON a, MonadBH m, WithBackend ElasticSearch7 m) =>
+  IndexName ->
+  Search ->
+  m [Hit a]
 pitSearch indexName search = do
   openResp <- openPointInTime indexName
   case openResp of
@@ -74,7 +79,7 @@
 -- For more information see
 -- <https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html>.
 openPointInTime ::
-  (MonadBH m) =>
+  (MonadBH m, WithBackend ElasticSearch7 m) =>
   IndexName ->
   m (ParsedEsResponse OpenPointInTimeResponse)
 openPointInTime indexName = performBHRequest $ Requests.openPointInTime indexName
@@ -84,7 +89,7 @@
 -- For more information see
 -- <https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html>.
 closePointInTime ::
-  (MonadBH m) =>
+  (MonadBH m, WithBackend ElasticSearch7 m) =>
   ClosePointInTime ->
   m (ParsedEsResponse ClosePointInTimeResponse)
 closePointInTime q = performBHRequest $ Requests.closePointInTime q
diff --git a/src/Database/Bloodhound/Internal/Client/BHRequest.hs b/src/Database/Bloodhound/Internal/Client/BHRequest.hs
--- a/src/Database/Bloodhound/Internal/Client/BHRequest.hs
+++ b/src/Database/Bloodhound/Internal/Client/BHRequest.hs
@@ -9,7 +9,7 @@
 -- Module : Database.Bloodhound.Client
 -- Copyright : (C) 2014, 2018 Chris Allen
 -- License : BSD-style (see the file LICENSE)
--- Maintainer : Gautier DI FOLCO <gautier.difolco@gmail.com>
+-- Maintainer : Chris Allen <cma@bitemyapp.com>
 -- Stability : provisional
 -- Portability : GHC
 --
diff --git a/src/Database/Bloodhound/Internal/Utils/Imports.hs b/src/Database/Bloodhound/Internal/Utils/Imports.hs
--- a/src/Database/Bloodhound/Internal/Utils/Imports.hs
+++ b/src/Database/Bloodhound/Internal/Utils/Imports.hs
@@ -66,7 +66,9 @@
 import qualified Network.HTTP.Types.Method as NHTM
 import Optics.Core as X
   ( Lens',
+    Prism',
     lens,
+    prism,
   )
 
 type LByteString = BL.ByteString
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Aggregation.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Aggregation.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Aggregation.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Aggregation.hs
@@ -35,6 +35,86 @@
   | SumAgg SumAggregation
   deriving stock (Eq, Show)
 
+aggregationTermsAggPrism :: Prism' Aggregation TermsAggregation
+aggregationTermsAggPrism = prism TermsAgg extract
+  where
+    extract s =
+      case s of
+        TermsAgg x -> Right x
+        _ -> Left s
+
+aggregationCardinalityAggPrism :: Prism' Aggregation CardinalityAggregation
+aggregationCardinalityAggPrism = prism CardinalityAgg extract
+  where
+    extract s =
+      case s of
+        CardinalityAgg x -> Right x
+        _ -> Left s
+
+aggregationDateHistogramAggPrism :: Prism' Aggregation DateHistogramAggregation
+aggregationDateHistogramAggPrism = prism DateHistogramAgg extract
+  where
+    extract s =
+      case s of
+        DateHistogramAgg x -> Right x
+        _ -> Left s
+
+aggregationValueCountAggPrism :: Prism' Aggregation ValueCountAggregation
+aggregationValueCountAggPrism = prism ValueCountAgg extract
+  where
+    extract s =
+      case s of
+        ValueCountAgg x -> Right x
+        _ -> Left s
+
+aggregationFilterAggPrism :: Prism' Aggregation FilterAggregation
+aggregationFilterAggPrism = prism FilterAgg extract
+  where
+    extract s =
+      case s of
+        FilterAgg x -> Right x
+        _ -> Left s
+
+aggregationDateRangeAggPrism :: Prism' Aggregation DateRangeAggregation
+aggregationDateRangeAggPrism = prism DateRangeAgg extract
+  where
+    extract s =
+      case s of
+        DateRangeAgg x -> Right x
+        _ -> Left s
+
+aggregationMissingAggPrism :: Prism' Aggregation MissingAggregation
+aggregationMissingAggPrism = prism MissingAgg extract
+  where
+    extract s =
+      case s of
+        MissingAgg x -> Right x
+        _ -> Left s
+
+aggregationTopHitsAggPrism :: Prism' Aggregation TopHitsAggregation
+aggregationTopHitsAggPrism = prism TopHitsAgg extract
+  where
+    extract s =
+      case s of
+        TopHitsAgg x -> Right x
+        _ -> Left s
+
+aggregationStatsAggPrism :: Prism' Aggregation StatisticsAggregation
+aggregationStatsAggPrism = prism StatsAgg extract
+  where
+    extract s =
+      case s of
+        StatsAgg x -> Right x
+        _ -> Left s
+
+aggregationSumAggPrism :: Prism' Aggregation SumAggregation
+aggregationSumAggPrism = prism SumAgg extract
+  where
+    extract s =
+      case s of
+        SumAgg x -> Right x
+        _ -> Left s
+
 instance ToJSON Aggregation where
   toJSON (TermsAgg (TermsAggregation term include exclude order minDocCount size shardSize collectMode executionHint termAggs)) =
     omitNulls
@@ -131,22 +211,22 @@
   }
   deriving stock (Eq, Show)
 
-taFromLens :: Lens' TopHitsAggregation (Maybe From)
-taFromLens = lens taFrom (\x y -> x {taFrom = y})
+topHitsAggregationFromLens :: Lens' TopHitsAggregation (Maybe From)
+topHitsAggregationFromLens = lens taFrom (\x y -> x {taFrom = y})
 
-taSizeLens :: Lens' TopHitsAggregation (Maybe Size)
-taSizeLens = lens taSize (\x y -> x {taSize = y})
+topHitsAggregationSizeLens :: Lens' TopHitsAggregation (Maybe Size)
+topHitsAggregationSizeLens = lens taSize (\x y -> x {taSize = y})
 
-taSortLens :: Lens' TopHitsAggregation (Maybe Sort)
-taSortLens = lens taSort (\x y -> x {taSort = y})
+topHitsAggregationSortLens :: Lens' TopHitsAggregation (Maybe Sort)
+topHitsAggregationSortLens = lens taSort (\x y -> x {taSort = y})
 
 data MissingAggregation = MissingAggregation
   { maField :: Text
   }
   deriving stock (Eq, Show)
 
-maFieldLens :: Lens' MissingAggregation Text
-maFieldLens = lens maField (\x y -> x {maField = y})
+missingAggregationFieldLens :: Lens' MissingAggregation Text
+missingAggregationFieldLens = lens maField (\x y -> x {maField = y})
 
 data TermsAggregation = TermsAggregation
   { term :: Either Text Text,
@@ -162,35 +242,35 @@
   }
   deriving stock (Eq, Show)
 
-termLens :: Lens' TermsAggregation (Either Text Text)
-termLens = lens term (\x y -> x {term = y})
+termAggregationTermLens :: Lens' TermsAggregation (Either Text Text)
+termAggregationTermLens = lens term (\x y -> x {term = y})
 
-termIncludeLens :: Lens' TermsAggregation (Maybe TermInclusion)
-termIncludeLens = lens termInclude (\x y -> x {termInclude = y})
+termAggregationIncludeLens :: Lens' TermsAggregation (Maybe TermInclusion)
+termAggregationIncludeLens = lens termInclude (\x y -> x {termInclude = y})
 
-termExcludeLens :: Lens' TermsAggregation (Maybe TermInclusion)
-termExcludeLens = lens termExclude (\x y -> x {termExclude = y})
+termAggregationExcludeLens :: Lens' TermsAggregation (Maybe TermInclusion)
+termAggregationExcludeLens = lens termExclude (\x y -> x {termExclude = y})
 
-termOrderLens :: Lens' TermsAggregation (Maybe TermOrder)
-termOrderLens = lens termOrder (\x y -> x {termOrder = y})
+termAggregationOrderLens :: Lens' TermsAggregation (Maybe TermOrder)
+termAggregationOrderLens = lens termOrder (\x y -> x {termOrder = y})
 
-termMinDocCountLens :: Lens' TermsAggregation (Maybe Int)
-termMinDocCountLens = lens termMinDocCount (\x y -> x {termMinDocCount = y})
+termAggregationMinDocCountLens :: Lens' TermsAggregation (Maybe Int)
+termAggregationMinDocCountLens = lens termMinDocCount (\x y -> x {termMinDocCount = y})
 
-termSizeLens :: Lens' TermsAggregation (Maybe Int)
-termSizeLens = lens termSize (\x y -> x {termSize = y})
+termAggregationSizeLens :: Lens' TermsAggregation (Maybe Int)
+termAggregationSizeLens = lens termSize (\x y -> x {termSize = y})
 
-termShardSizeLens :: Lens' TermsAggregation (Maybe Int)
-termShardSizeLens = lens termShardSize (\x y -> x {termShardSize = y})
+termAggregationShardSizeLens :: Lens' TermsAggregation (Maybe Int)
+termAggregationShardSizeLens = lens termShardSize (\x y -> x {termShardSize = y})
 
-termCollectModeLens :: Lens' TermsAggregation (Maybe CollectionMode)
-termCollectModeLens = lens termCollectMode (\x y -> x {termCollectMode = y})
+termAggregationCollectModeLens :: Lens' TermsAggregation (Maybe CollectionMode)
+termAggregationCollectModeLens = lens termCollectMode (\x y -> x {termCollectMode = y})
 
-termExecutionHintLens :: Lens' TermsAggregation (Maybe ExecutionHint)
-termExecutionHintLens = lens termExecutionHint (\x y -> x {termExecutionHint = y})
+termAggregationExecutionHintLens :: Lens' TermsAggregation (Maybe ExecutionHint)
+termAggregationExecutionHintLens = lens termExecutionHint (\x y -> x {termExecutionHint = y})
 
-termAggsLens :: Lens' TermsAggregation (Maybe Aggregations)
-termAggsLens = lens termAggs (\x y -> x {termAggs = y})
+termAggregationAggsLens :: Lens' TermsAggregation (Maybe Aggregations)
+termAggregationAggsLens = lens termAggs (\x y -> x {termAggs = y})
 
 data CardinalityAggregation = CardinalityAggregation
   { cardinalityField :: FieldName,
@@ -198,11 +278,11 @@
   }
   deriving stock (Eq, Show)
 
-cardinalityFieldLens :: Lens' CardinalityAggregation FieldName
-cardinalityFieldLens = lens cardinalityField (\x y -> x {cardinalityField = y})
+cardinalityAggregationFieldLens :: Lens' CardinalityAggregation FieldName
+cardinalityAggregationFieldLens = lens cardinalityField (\x y -> x {cardinalityField = y})
 
-precisionThresholdLens :: Lens' CardinalityAggregation (Maybe Int)
-precisionThresholdLens = lens precisionThreshold (\x y -> x {precisionThreshold = y})
+cardinalityAggregationPrecisionThresholdLens :: Lens' CardinalityAggregation (Maybe Int)
+cardinalityAggregationPrecisionThresholdLens = lens precisionThreshold (\x y -> x {precisionThreshold = y})
 
 data DateHistogramAggregation = DateHistogramAggregation
   { dateField :: FieldName,
@@ -217,29 +297,29 @@
   }
   deriving stock (Eq, Show)
 
-dateFieldLens :: Lens' DateHistogramAggregation FieldName
-dateFieldLens = lens dateField (\x y -> x {dateField = y})
+dateHistogramAggregationFieldLens :: Lens' DateHistogramAggregation FieldName
+dateHistogramAggregationFieldLens = lens dateField (\x y -> x {dateField = y})
 
-dateIntervalLens :: Lens' DateHistogramAggregation Interval
-dateIntervalLens = lens dateInterval (\x y -> x {dateInterval = y})
+dateHistogramAggregationIntervalLens :: Lens' DateHistogramAggregation Interval
+dateHistogramAggregationIntervalLens = lens dateInterval (\x y -> x {dateInterval = y})
 
-dateFormatLens :: Lens' DateHistogramAggregation (Maybe Text)
-dateFormatLens = lens dateFormat (\x y -> x {dateFormat = y})
+dateHistogramAggregationFormatLens :: Lens' DateHistogramAggregation (Maybe Text)
+dateHistogramAggregationFormatLens = lens dateFormat (\x y -> x {dateFormat = y})
 
-datePreZoneLens :: Lens' DateHistogramAggregation (Maybe Text)
-datePreZoneLens = lens datePreZone (\x y -> x {datePreZone = y})
+dateHistogramAggregationPreZoneLens :: Lens' DateHistogramAggregation (Maybe Text)
+dateHistogramAggregationPreZoneLens = lens datePreZone (\x y -> x {datePreZone = y})
 
-datePostZoneLens :: Lens' DateHistogramAggregation (Maybe Text)
-datePostZoneLens = lens datePostZone (\x y -> x {datePostZone = y})
+dateHistogramAggregationPostZoneLens :: Lens' DateHistogramAggregation (Maybe Text)
+dateHistogramAggregationPostZoneLens = lens datePostZone (\x y -> x {datePostZone = y})
 
-datePreOffsetLens :: Lens' DateHistogramAggregation (Maybe Text)
-datePreOffsetLens = lens datePreOffset (\x y -> x {datePreOffset = y})
+dateHistogramAggregationPreOffsetLens :: Lens' DateHistogramAggregation (Maybe Text)
+dateHistogramAggregationPreOffsetLens = lens datePreOffset (\x y -> x {datePreOffset = y})
 
-datePostOffsetLens :: Lens' DateHistogramAggregation (Maybe Text)
-datePostOffsetLens = lens datePostOffset (\x y -> x {datePostOffset = y})
+dateHistogramAggregationPostOffsetLens :: Lens' DateHistogramAggregation (Maybe Text)
+dateHistogramAggregationPostOffsetLens = lens datePostOffset (\x y -> x {datePostOffset = y})
 
-dateAggsLens :: Lens' DateHistogramAggregation (Maybe Aggregations)
-dateAggsLens = lens dateAggs (\x y -> x {dateAggs = y})
+dateHistogramAggregationAggsLens :: Lens' DateHistogramAggregation (Maybe Aggregations)
+dateHistogramAggregationAggsLens = lens dateAggs (\x y -> x {dateAggs = y})
 
 data DateRangeAggregation = DateRangeAggregation
   { draField :: FieldName,
@@ -256,14 +336,14 @@
         "ranges" .= toList draRanges
       ]
 
-draFieldLens :: Lens' DateRangeAggregation FieldName
-draFieldLens = lens draField (\x y -> x {draField = y})
+dateRangeAggregationFieldLens :: Lens' DateRangeAggregation FieldName
+dateRangeAggregationFieldLens = lens draField (\x y -> x {draField = y})
 
-draFormatLens :: Lens' DateRangeAggregation (Maybe Text)
-draFormatLens = lens draFormat (\x y -> x {draFormat = y})
+dateRangeAggregationFormatLens :: Lens' DateRangeAggregation (Maybe Text)
+dateRangeAggregationFormatLens = lens draFormat (\x y -> x {draFormat = y})
 
-draRangesLens :: Lens' DateRangeAggregation (NonEmpty DateRangeAggRange)
-draRangesLens = lens draRanges (\x y -> x {draRanges = y})
+dateRangeAggregationRangesLens :: Lens' DateRangeAggregation (NonEmpty DateRangeAggRange)
+dateRangeAggregationRangesLens = lens draRanges (\x y -> x {draRanges = y})
 
 data DateRangeAggRange
   = DateRangeFrom DateMathExpr
@@ -271,6 +351,30 @@
   | DateRangeFromAndTo DateMathExpr DateMathExpr
   deriving stock (Eq, Show)
 
+dateRangeAggRangeDateRangeFromPrism :: Prism' DateRangeAggRange DateMathExpr
+dateRangeAggRangeDateRangeFromPrism = prism DateRangeFrom extract
+  where
+    extract s =
+      case s of
+        DateRangeFrom x -> Right x
+        _ -> Left s
+
+dateRangeAggRangeDateRangeToPrism :: Prism' DateRangeAggRange DateMathExpr
+dateRangeAggRangeDateRangeToPrism = prism DateRangeTo extract
+  where
+    extract s =
+      case s of
+        DateRangeTo x -> Right x
+        _ -> Left s
+
+dateRangeAggRangeDateRangeFromAndToPrism :: Prism' DateRangeAggRange (DateMathExpr, DateMathExpr)
+dateRangeAggRangeDateRangeFromAndToPrism = prism (uncurry DateRangeFromAndTo) extract
+  where
+    extract s =
+      case s of
+        DateRangeFromAndTo x y -> Right (x, y)
+        _ -> Left s
+
 instance ToJSON DateRangeAggRange where
   toJSON (DateRangeFrom e) = object ["from" .= e]
   toJSON (DateRangeTo e) = object ["to" .= e]
@@ -289,11 +393,11 @@
   }
   deriving stock (Eq, Show)
 
-faFilterLens :: Lens' FilterAggregation Filter
-faFilterLens = lens faFilter (\x y -> x {faFilter = y})
+filterAggregationFilterLens :: Lens' FilterAggregation Filter
+filterAggregationFilterLens = lens faFilter (\x y -> x {faFilter = y})
 
-faAggsLens :: Lens' FilterAggregation (Maybe Aggregations)
-faAggsLens = lens faAggs (\x y -> x {faAggs = y})
+filterAggregationAggsLens :: Lens' FilterAggregation (Maybe Aggregations)
+filterAggregationAggsLens = lens faAggs (\x y -> x {faAggs = y})
 
 data StatisticsAggregation = StatisticsAggregation
   { statsType :: StatsType,
@@ -301,11 +405,11 @@
   }
   deriving stock (Eq, Show)
 
-statsTypeLens :: Lens' StatisticsAggregation StatsType
-statsTypeLens = lens statsType (\x y -> x {statsType = y})
+statisticsAggregationTypeLens :: Lens' StatisticsAggregation StatsType
+statisticsAggregationTypeLens = lens statsType (\x y -> x {statsType = y})
 
-statsFieldLens :: Lens' StatisticsAggregation FieldName
-statsFieldLens = lens statsField (\x y -> x {statsField = y})
+statisticsAggregationFieldLens :: Lens' StatisticsAggregation FieldName
+statisticsAggregationFieldLens = lens statsField (\x y -> x {statsField = y})
 
 data StatsType
   = Basic
@@ -400,11 +504,11 @@
   toJSON (TermOrder termSortField termSortOrder) =
     object [fromText termSortField .= termSortOrder]
 
-termSortFieldLens :: Lens' TermOrder Text
-termSortFieldLens = lens termSortField (\x y -> x {termSortField = y})
+termOrderSortFieldLens :: Lens' TermOrder Text
+termOrderSortFieldLens = lens termSortField (\x y -> x {termSortField = y})
 
-termSortOrderLens :: Lens' TermOrder SortOrder
-termSortOrderLens = lens termSortOrder (\x y -> x {termSortOrder = y})
+termOrderSortOrderLens :: Lens' TermOrder SortOrder
+termOrderSortOrderLens = lens termSortOrder (\x y -> x {termSortOrder = y})
 
 data CollectionMode
   = BreadthFirst
@@ -479,7 +583,7 @@
     TermsResult
       <$> v .: "key"
       <*> v .: "doc_count"
-      <*> (pure $ getNamedSubAgg v ["key", "doc_count"])
+      <*> pure (getNamedSubAgg v ["key", "doc_count"])
   parseJSON _ = mempty
 
 instance BucketAggregation TermsResult where
@@ -487,14 +591,14 @@
   docCount = termsDocCount
   aggs = termsAggs
 
-termKeyLens :: Lens' TermsResult BucketValue
-termKeyLens = lens termKey (\x y -> x {termKey = y})
+termsResultKeyLens :: Lens' TermsResult BucketValue
+termsResultKeyLens = lens termKey (\x y -> x {termKey = y})
 
-termsDocCountLens :: Lens' TermsResult Int
-termsDocCountLens = lens termsDocCount (\x y -> x {termsDocCount = y})
+termsResultDocCountLens :: Lens' TermsResult Int
+termsResultDocCountLens = lens termsDocCount (\x y -> x {termsDocCount = y})
 
-termsAggsLens :: Lens' TermsResult (Maybe AggregationResults)
-termsAggsLens = lens termsAggs (\x y -> x {termsAggs = y})
+termsResultAggsLens :: Lens' TermsResult (Maybe AggregationResults)
+termsResultAggsLens = lens termsAggs (\x y -> x {termsAggs = y})
 
 data DateHistogramResult = DateHistogramResult
   { dateKey :: Int,
@@ -525,17 +629,17 @@
   docCount = dateDocCount
   aggs = dateHistogramAggs
 
-dateKeyLens :: Lens' DateHistogramResult Int
-dateKeyLens = lens dateKey (\x y -> x {dateKey = y})
+dateHistogramResultKeyLens :: Lens' DateHistogramResult Int
+dateHistogramResultKeyLens = lens dateKey (\x y -> x {dateKey = y})
 
-dateKeyStrLens :: Lens' DateHistogramResult (Maybe Text)
-dateKeyStrLens = lens dateKeyStr (\x y -> x {dateKeyStr = y})
+dateHistogramResultKeyStrLens :: Lens' DateHistogramResult (Maybe Text)
+dateHistogramResultKeyStrLens = lens dateKeyStr (\x y -> x {dateKeyStr = y})
 
-dateDocCountLens :: Lens' DateHistogramResult Int
-dateDocCountLens = lens dateDocCount (\x y -> x {dateDocCount = y})
+dateHistogramResultDocCountLens :: Lens' DateHistogramResult Int
+dateHistogramResultDocCountLens = lens dateDocCount (\x y -> x {dateDocCount = y})
 
-dateHistogramAggsLens :: Lens' DateHistogramResult (Maybe AggregationResults)
-dateHistogramAggsLens = lens dateHistogramAggs (\x y -> x {dateHistogramAggs = y})
+dateHistogramResultAggsLens :: Lens' DateHistogramResult (Maybe AggregationResults)
+dateHistogramResultAggsLens = lens dateHistogramAggs (\x y -> x {dateHistogramAggs = y})
 
 data DateRangeResult = DateRangeResult
   { dateRangeKey :: Text,
@@ -576,26 +680,26 @@
   docCount = dateRangeDocCount
   aggs = dateRangeAggs
 
-dateRangeKeyLens :: Lens' DateRangeResult Text
-dateRangeKeyLens = lens dateRangeKey (\x y -> x {dateRangeKey = y})
+dateRangeResultKeyLens :: Lens' DateRangeResult Text
+dateRangeResultKeyLens = lens dateRangeKey (\x y -> x {dateRangeKey = y})
 
-dateRangeFromLens :: Lens' DateRangeResult (Maybe UTCTime)
-dateRangeFromLens = lens dateRangeFrom (\x y -> x {dateRangeFrom = y})
+dateRangeResultFromLens :: Lens' DateRangeResult (Maybe UTCTime)
+dateRangeResultFromLens = lens dateRangeFrom (\x y -> x {dateRangeFrom = y})
 
-dateRangeFromAsStringLens :: Lens' DateRangeResult (Maybe Text)
-dateRangeFromAsStringLens = lens dateRangeFromAsString (\x y -> x {dateRangeFromAsString = y})
+dateRangeResultFromAsStringLens :: Lens' DateRangeResult (Maybe Text)
+dateRangeResultFromAsStringLens = lens dateRangeFromAsString (\x y -> x {dateRangeFromAsString = y})
 
-dateRangeToLens :: Lens' DateRangeResult (Maybe UTCTime)
-dateRangeToLens = lens dateRangeTo (\x y -> x {dateRangeTo = y})
+dateRangeResultToLens :: Lens' DateRangeResult (Maybe UTCTime)
+dateRangeResultToLens = lens dateRangeTo (\x y -> x {dateRangeTo = y})
 
-dateRangeToAsStringLens :: Lens' DateRangeResult (Maybe Text)
-dateRangeToAsStringLens = lens dateRangeToAsString (\x y -> x {dateRangeToAsString = y})
+dateRangeResultToAsStringLens :: Lens' DateRangeResult (Maybe Text)
+dateRangeResultToAsStringLens = lens dateRangeToAsString (\x y -> x {dateRangeToAsString = y})
 
-dateRangeDocCountLens :: Lens' DateRangeResult Int
-dateRangeDocCountLens = lens dateRangeDocCount (\x y -> x {dateRangeDocCount = y})
+dateRangeResultDocCountLens :: Lens' DateRangeResult Int
+dateRangeResultDocCountLens = lens dateRangeDocCount (\x y -> x {dateRangeDocCount = y})
 
-dateRangeAggsLens :: Lens' DateRangeResult (Maybe AggregationResults)
-dateRangeAggsLens = lens dateRangeAggs (\x y -> x {dateRangeAggs = y})
+dateRangeResultAggsLens :: Lens' DateRangeResult (Maybe AggregationResults)
+dateRangeResultAggsLens = lens dateRangeAggs (\x y -> x {dateRangeAggs = y})
 
 toTerms :: Key -> AggregationResults -> Maybe (Bucket TermsResult)
 toTerms = toAggResult
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Count.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Count.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Count.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Count.hs
@@ -6,11 +6,11 @@
     CountShards (..),
 
     -- * Optics
-    crCountLens,
-    crShardsLens,
-    csTotalLens,
-    csSuccessfulLens,
-    csFailedLens,
+    countResponseCountLens,
+    countResponseShardsLens,
+    countShardsTotalLens,
+    countShardsSuccessfulLens,
+    countShardsFailedLens,
   )
 where
 
@@ -42,11 +42,11 @@
           <*> o
             .: "_shards"
 
-crCountLens :: Lens' CountResponse Natural
-crCountLens = lens crCount (\x y -> x {crCount = y})
+countResponseCountLens :: Lens' CountResponse Natural
+countResponseCountLens = lens crCount (\x y -> x {crCount = y})
 
-crShardsLens :: Lens' CountResponse CountShards
-crShardsLens = lens crShards (\x y -> x {crShards = y})
+countResponseShardsLens :: Lens' CountResponse CountShards
+countResponseShardsLens = lens crShards (\x y -> x {crShards = y})
 
 data CountShards = CountShards
   { csTotal :: Int,
@@ -67,11 +67,11 @@
           <*> o
             .: "failed"
 
-csTotalLens :: Lens' CountShards Int
-csTotalLens = lens csTotal (\x y -> x {csTotal = y})
+countShardsTotalLens :: Lens' CountShards Int
+countShardsTotalLens = lens csTotal (\x y -> x {csTotal = y})
 
-csSuccessfulLens :: Lens' CountShards Int
-csSuccessfulLens = lens csSuccessful (\x y -> x {csSuccessful = y})
+countShardsSuccessfulLens :: Lens' CountShards Int
+countShardsSuccessfulLens = lens csSuccessful (\x y -> x {csSuccessful = y})
 
-csFailedLens :: Lens' CountShards Int
-csFailedLens = lens csFailed (\x y -> x {csFailed = y})
+countShardsFailedLens :: Lens' CountShards Int
+countShardsFailedLens = lens csFailed (\x y -> x {csFailed = y})
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Highlight.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Highlight.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Highlight.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Highlight.hs
@@ -15,6 +15,12 @@
   }
   deriving stock (Eq, Show)
 
+highlightsGlobalsettingsLens :: Lens' Highlights (Maybe HighlightSettings)
+highlightsGlobalsettingsLens = lens globalsettings (\x y -> x {globalsettings = y})
+
+highlightsHighlightFieldsLens :: Lens' Highlights [FieldHighlight]
+highlightsHighlightFieldsLens = lens highlightFields (\x y -> x {highlightFields = y})
+
 instance ToJSON Highlights where
   toJSON (Highlights global fields) =
     omitNulls
@@ -22,10 +28,18 @@
           : highlightSettingsPairs global
       )
 
-data FieldHighlight
-  = FieldHighlight FieldName (Maybe HighlightSettings)
+data FieldHighlight = FieldHighlight
+  { fieldHighlightName :: FieldName,
+    fieldHighlightSettings :: Maybe HighlightSettings
+  }
   deriving stock (Eq, Show)
 
+fieldHighlightNameLens :: Lens' FieldHighlight FieldName
+fieldHighlightNameLens = lens fieldHighlightName (\x y -> x {fieldHighlightName = y})
+
+fieldHighlightSettingsLens :: Lens' FieldHighlight (Maybe HighlightSettings)
+fieldHighlightSettingsLens = lens fieldHighlightSettings (\x y -> x {fieldHighlightSettings = y})
+
 instance ToJSON FieldHighlight where
   toJSON (FieldHighlight (FieldName fName) (Just fSettings)) =
     object [fromText fName .= fSettings]
@@ -38,6 +52,30 @@
   | FastVector FastVectorHighlight
   deriving stock (Eq, Show)
 
+highlightSettingsPlainPrism :: Prism' HighlightSettings PlainHighlight
+highlightSettingsPlainPrism = prism Plain extract
+  where
+    extract hs =
+      case hs of
+        Plain x -> Right x
+        _ -> Left hs
+
+highlightSettingsPostingsPrism :: Prism' HighlightSettings PostingsHighlight
+highlightSettingsPostingsPrism = prism Postings extract
+  where
+    extract hs =
+      case hs of
+        Postings x -> Right x
+        _ -> Left hs
+
+highlightSettingsFastVectorPrism :: Prism' HighlightSettings FastVectorHighlight
+highlightSettingsFastVectorPrism = prism FastVector extract
+  where
+    extract hs =
+      case hs of
+        FastVector x -> Right x
+        _ -> Left hs
+
 instance ToJSON HighlightSettings where
   toJSON hs = omitNulls (highlightSettingsPairs (Just hs))
 
@@ -47,11 +85,19 @@
   }
   deriving stock (Eq, Show)
 
+plainHighlightCommonLens :: Lens' PlainHighlight (Maybe CommonHighlight)
+plainHighlightCommonLens = lens plainCommon (\x y -> x {plainCommon = y})
+
+plainHighlightNonPostLens :: Lens' PlainHighlight (Maybe NonPostings)
+plainHighlightNonPostLens = lens plainNonPost (\x y -> x {plainNonPost = y})
+
 -- This requires that index_options are set to 'offset' in the mapping.
-data PostingsHighlight
-  = PostingsHighlight (Maybe CommonHighlight)
+newtype PostingsHighlight = PostingsHighlight {getPostingsHighlight :: Maybe CommonHighlight}
   deriving stock (Eq, Show)
 
+postingsHighlightLens :: Lens' PostingsHighlight (Maybe CommonHighlight)
+postingsHighlightLens = lens getPostingsHighlight (\x y -> x {getPostingsHighlight = y})
+
 -- This requires that term_vector is set to 'with_positions_offsets' in the mapping.
 data FastVectorHighlight = FastVectorHighlight
   { fvCommon :: Maybe CommonHighlight,
@@ -64,6 +110,27 @@
   }
   deriving stock (Eq, Show)
 
+fastVectorHighlightFvCommonLens :: Lens' FastVectorHighlight (Maybe CommonHighlight)
+fastVectorHighlightFvCommonLens = lens fvCommon (\x y -> x {fvCommon = y})
+
+fastVectorHighlightFvNonPostSettingsLens :: Lens' FastVectorHighlight (Maybe NonPostings)
+fastVectorHighlightFvNonPostSettingsLens = lens fvNonPostSettings (\x y -> x {fvNonPostSettings = y})
+
+fastVectorHighlightBoundaryCharsLens :: Lens' FastVectorHighlight (Maybe Text)
+fastVectorHighlightBoundaryCharsLens = lens boundaryChars (\x y -> x {boundaryChars = y})
+
+fastVectorHighlightBoundaryMaxScanLens :: Lens' FastVectorHighlight (Maybe Int)
+fastVectorHighlightBoundaryMaxScanLens = lens boundaryMaxScan (\x y -> x {boundaryMaxScan = y})
+
+fastVectorHighlightFragmentOffsetLens :: Lens' FastVectorHighlight (Maybe Int)
+fastVectorHighlightFragmentOffsetLens = lens fragmentOffset (\x y -> x {fragmentOffset = y})
+
+fastVectorHighlightMatchedFieldsLens :: Lens' FastVectorHighlight [Text]
+fastVectorHighlightMatchedFieldsLens = lens matchedFields (\x y -> x {matchedFields = y})
+
+fastVectorHighlightPhraseLimitLens :: Lens' FastVectorHighlight (Maybe Int)
+fastVectorHighlightPhraseLimitLens = lens phraseLimit (\x y -> x {phraseLimit = y})
+
 data CommonHighlight = CommonHighlight
   { order :: Maybe Text,
     forceSource :: Maybe Bool,
@@ -75,12 +142,39 @@
   }
   deriving stock (Eq, Show)
 
+commonHighlightOrderLens :: Lens' CommonHighlight (Maybe Text)
+commonHighlightOrderLens = lens order (\x y -> x {order = y})
+
+commonHighlightForceSourceLens :: Lens' CommonHighlight (Maybe Bool)
+commonHighlightForceSourceLens = lens forceSource (\x y -> x {forceSource = y})
+
+commonHighlightTagLens :: Lens' CommonHighlight (Maybe HighlightTag)
+commonHighlightTagLens = lens tag (\x y -> x {tag = y})
+
+commonHighlightEncoderLens :: Lens' CommonHighlight (Maybe HighlightEncoder)
+commonHighlightEncoderLens = lens encoder (\x y -> x {encoder = y})
+
+commonHighlightNoMatchSizeLens :: Lens' CommonHighlight (Maybe Int)
+commonHighlightNoMatchSizeLens = lens noMatchSize (\x y -> x {noMatchSize = y})
+
+commonHighlightHighlightQueryLens :: Lens' CommonHighlight (Maybe Query)
+commonHighlightHighlightQueryLens = lens highlightQuery (\x y -> x {highlightQuery = y})
+
+commonHighlightRequireFieldMatchLens :: Lens' CommonHighlight (Maybe Bool)
+commonHighlightRequireFieldMatchLens = lens requireFieldMatch (\x y -> x {requireFieldMatch = y})
+
 -- Settings that are only applicable to FastVector and Plain highlighters.
 data NonPostings = NonPostings
   { fragmentSize :: Maybe Int,
     numberOfFragments :: Maybe Int
   }
   deriving stock (Eq, Show)
+
+nonPostingsFragmentSizeLens :: Lens' NonPostings (Maybe Int)
+nonPostingsFragmentSizeLens = lens fragmentSize (\x y -> x {fragmentSize = y})
+
+nonPostingsNumberOfFragmentsLens :: Lens' NonPostings (Maybe Int)
+nonPostingsNumberOfFragmentsLens = lens numberOfFragments (\x y -> x {numberOfFragments = y})
 
 data HighlightEncoder
   = DefaultEncoder
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Indices.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Indices.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Indices.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Indices.hs
@@ -40,45 +40,44 @@
     defaultIndexSettings,
 
     -- * Optics
-    nameLens,
-    clusterNameLens,
-    clusterUuidLens,
-    versionLens,
-    taglineLens,
-    indexShardsLens,
-    indexReplicasLens,
-    indexMappingsLimitsLens,
-    indexMappingsLimitDepthLens,
-    indexMappingsLimitNestedFieldsLens,
-    indexMappingsLimitNestedObjectsLens,
-    indexMappingsLimitFieldNameLengthLens,
-    maxNumSegmentsLens,
-    onlyExpungeDeletesLens,
-    flushAfterOptimizeLens,
-    sSummaryIndexNameLens,
-    sSummaryFixedSettingsLens,
-    sSummaryUpdateableLens,
-    fieldTypeLens,
-    templatePatternsLens,
-    templateSettingsLens,
-    templateMappingsLens,
+    statusNameLens,
+    statusClusterNameLens,
+    statusClusterUuidLens,
+    statusVersionLens,
+    statusTaglineLens,
+    indexSettingsShardsLens,
+    indexSettingsReplicasLens,
+    indexSettingsMappingsLimitsLens,
+    indexMappingsLimitsDepthLens,
+    indexMappingsLimitsNestedFieldsLens,
+    indexMappingsLimitsNestedObjectsLens,
+    indexMappingsLimitsFieldNameLengthLens,
+    forceMergeIndexSettingsMaxNumSegmentsLens,
+    forceMergeIndexSettingsOnlyExpungeDeletesLens,
+    forceMergeIndexSettingsFlushAfterOptimizeLens,
+    indexSettingsSummarySummaryIndexNameLens,
+    indexSettingsSummarySummaryFixedSettingsLens,
+    indexSettingsSummarySummaryUpdateableLens,
+    fieldDefinitionTypeLens,
+    indexTemplatePatternsLens,
+    indexTemplateSettingsLens,
+    indexTemplateMappingsLens,
     mappingFieldNameLens,
-    fieldDefinitionLens,
+    mappingFieldDefinitionLens,
     mappingFieldsLens,
-    srcIndexLens,
+    indexAliasSrcIndexLens,
     indexAliasLens,
-    aliasCreateRoutingLens,
-    aliasCreateFilterLens,
+    indexAliasCreateRoutingLens,
+    indexAliasCreateFilterLens,
     routingValueLens,
     indexAliasesSummaryLens,
     indexAliasSummaryAliasLens,
     indexAliasSummaryCreateLens,
-    idsVersionControlLens,
-    idsJoinRelationLens,
+    indexDocumentSettingsVersionControlLens,
+    indexDocumentSettingsJoinRelationLens,
   )
 where
 
-import Control.Monad.Except
 import qualified Data.Aeson.KeyMap as X
 import qualified Data.HashMap.Strict as HM
 import Data.Maybe (mapMaybe)
@@ -122,20 +121,20 @@
         .: "tagline"
   parseJSON _ = empty
 
-nameLens :: Lens' Status Text
-nameLens = lens name (\x y -> x {name = y})
+statusNameLens :: Lens' Status Text
+statusNameLens = lens name (\x y -> x {name = y})
 
-clusterNameLens :: Lens' Status Text
-clusterNameLens = lens cluster_name (\x y -> x {cluster_name = y})
+statusClusterNameLens :: Lens' Status Text
+statusClusterNameLens = lens cluster_name (\x y -> x {cluster_name = y})
 
-clusterUuidLens :: Lens' Status Text
-clusterUuidLens = lens cluster_uuid (\x y -> x {cluster_uuid = y})
+statusClusterUuidLens :: Lens' Status Text
+statusClusterUuidLens = lens cluster_uuid (\x y -> x {cluster_uuid = y})
 
-versionLens :: Lens' Status Version
-versionLens = lens version (\x y -> x {version = y})
+statusVersionLens :: Lens' Status Version
+statusVersionLens = lens version (\x y -> x {version = y})
 
-taglineLens :: Lens' Status Text
-taglineLens = lens tagline (\x y -> x {tagline = y})
+statusTaglineLens :: Lens' Status Text
+statusTaglineLens = lens tagline (\x y -> x {tagline = y})
 
 -- | 'IndexSettings' is used to configure the shards and replicas when
 --   you create an Elasticsearch Index.
@@ -173,14 +172,14 @@
             .:? "mapping"
             .!= defaultIndexMappingsLimits
 
-indexShardsLens :: Lens' IndexSettings ShardCount
-indexShardsLens = lens indexShards (\x y -> x {indexShards = y})
+indexSettingsShardsLens :: Lens' IndexSettings ShardCount
+indexSettingsShardsLens = lens indexShards (\x y -> x {indexShards = y})
 
-indexReplicasLens :: Lens' IndexSettings ReplicaCount
-indexReplicasLens = lens indexReplicas (\x y -> x {indexReplicas = y})
+indexSettingsReplicasLens :: Lens' IndexSettings ReplicaCount
+indexSettingsReplicasLens = lens indexReplicas (\x y -> x {indexReplicas = y})
 
-indexMappingsLimitsLens :: Lens' IndexSettings IndexMappingsLimits
-indexMappingsLimitsLens = lens indexMappingsLimits (\x y -> x {indexMappingsLimits = y})
+indexSettingsMappingsLimitsLens :: Lens' IndexSettings IndexMappingsLimits
+indexSettingsMappingsLimitsLens = lens indexMappingsLimits (\x y -> x {indexMappingsLimits = y})
 
 -- | 'defaultIndexSettings' is an 'IndexSettings' with 3 shards and
 --   2 replicas.
@@ -225,17 +224,17 @@
         f <- o .: name
         f .: "limit"
 
-indexMappingsLimitDepthLens :: Lens' IndexMappingsLimits (Maybe Int)
-indexMappingsLimitDepthLens = lens indexMappingsLimitDepth (\x y -> x {indexMappingsLimitDepth = y})
+indexMappingsLimitsDepthLens :: Lens' IndexMappingsLimits (Maybe Int)
+indexMappingsLimitsDepthLens = lens indexMappingsLimitDepth (\x y -> x {indexMappingsLimitDepth = y})
 
-indexMappingsLimitNestedFieldsLens :: Lens' IndexMappingsLimits (Maybe Int)
-indexMappingsLimitNestedFieldsLens = lens indexMappingsLimitNestedFields (\x y -> x {indexMappingsLimitNestedFields = y})
+indexMappingsLimitsNestedFieldsLens :: Lens' IndexMappingsLimits (Maybe Int)
+indexMappingsLimitsNestedFieldsLens = lens indexMappingsLimitNestedFields (\x y -> x {indexMappingsLimitNestedFields = y})
 
-indexMappingsLimitNestedObjectsLens :: Lens' IndexMappingsLimits (Maybe Int)
-indexMappingsLimitNestedObjectsLens = lens indexMappingsLimitNestedObjects (\x y -> x {indexMappingsLimitNestedObjects = y})
+indexMappingsLimitsNestedObjectsLens :: Lens' IndexMappingsLimits (Maybe Int)
+indexMappingsLimitsNestedObjectsLens = lens indexMappingsLimitNestedObjects (\x y -> x {indexMappingsLimitNestedObjects = y})
 
-indexMappingsLimitFieldNameLengthLens :: Lens' IndexMappingsLimits (Maybe Int)
-indexMappingsLimitFieldNameLengthLens = lens indexMappingsLimitFieldNameLength (\x y -> x {indexMappingsLimitFieldNameLength = y})
+indexMappingsLimitsFieldNameLengthLens :: Lens' IndexMappingsLimits (Maybe Int)
+indexMappingsLimitsFieldNameLengthLens = lens indexMappingsLimitFieldNameLength (\x y -> x {indexMappingsLimitFieldNameLength = y})
 
 defaultIndexMappingsLimits :: IndexMappingsLimits
 defaultIndexMappingsLimits = IndexMappingsLimits Nothing Nothing Nothing Nothing
@@ -253,14 +252,14 @@
   }
   deriving stock (Eq, Show)
 
-maxNumSegmentsLens :: Lens' ForceMergeIndexSettings (Maybe Int)
-maxNumSegmentsLens = lens maxNumSegments (\x y -> x {maxNumSegments = y})
+forceMergeIndexSettingsMaxNumSegmentsLens :: Lens' ForceMergeIndexSettings (Maybe Int)
+forceMergeIndexSettingsMaxNumSegmentsLens = lens maxNumSegments (\x y -> x {maxNumSegments = y})
 
-onlyExpungeDeletesLens :: Lens' ForceMergeIndexSettings Bool
-onlyExpungeDeletesLens = lens onlyExpungeDeletes (\x y -> x {onlyExpungeDeletes = y})
+forceMergeIndexSettingsOnlyExpungeDeletesLens :: Lens' ForceMergeIndexSettings Bool
+forceMergeIndexSettingsOnlyExpungeDeletesLens = lens onlyExpungeDeletes (\x y -> x {onlyExpungeDeletes = y})
 
-flushAfterOptimizeLens :: Lens' ForceMergeIndexSettings Bool
-flushAfterOptimizeLens = lens flushAfterOptimize (\x y -> x {flushAfterOptimize = y})
+forceMergeIndexSettingsFlushAfterOptimizeLens :: Lens' ForceMergeIndexSettings Bool
+forceMergeIndexSettingsFlushAfterOptimizeLens = lens flushAfterOptimize (\x y -> x {flushAfterOptimize = y})
 
 -- | 'defaultForceMergeIndexSettings' implements the default settings that
 --   Elasticsearch uses for index optimization. 'maxNumSegments' is Nothing,
@@ -387,67 +386,67 @@
         numberOfReplicas
           `taggedAt` ["index", "number_of_replicas"]
           <|> autoExpandReplicas
-            `taggedAt` ["index", "auto_expand_replicas"]
+          `taggedAt` ["index", "auto_expand_replicas"]
           <|> refreshInterval
-            `taggedAt` ["index", "refresh_interval"]
+          `taggedAt` ["index", "refresh_interval"]
           <|> indexConcurrency
-            `taggedAt` ["index", "concurrency"]
+          `taggedAt` ["index", "concurrency"]
           <|> failOnMergeFailure
-            `taggedAt` ["index", "fail_on_merge_failure"]
+          `taggedAt` ["index", "fail_on_merge_failure"]
           <|> translogFlushThresholdOps
-            `taggedAt` ["index", "translog", "flush_threshold_ops"]
+          `taggedAt` ["index", "translog", "flush_threshold_ops"]
           <|> translogFlushThresholdSize
-            `taggedAt` ["index", "translog", "flush_threshold_size"]
+          `taggedAt` ["index", "translog", "flush_threshold_size"]
           <|> translogFlushThresholdPeriod
-            `taggedAt` ["index", "translog", "flush_threshold_period"]
+          `taggedAt` ["index", "translog", "flush_threshold_period"]
           <|> translogDisableFlush
-            `taggedAt` ["index", "translog", "disable_flush"]
+          `taggedAt` ["index", "translog", "disable_flush"]
           <|> cacheFilterMaxSize
-            `taggedAt` ["index", "cache", "filter", "max_size"]
+          `taggedAt` ["index", "cache", "filter", "max_size"]
           <|> cacheFilterExpire
-            `taggedAt` ["index", "cache", "filter", "expire"]
+          `taggedAt` ["index", "cache", "filter", "expire"]
           <|> gatewaySnapshotInterval
-            `taggedAt` ["index", "gateway", "snapshot_interval"]
+          `taggedAt` ["index", "gateway", "snapshot_interval"]
           <|> routingAllocationInclude
-            `taggedAt` ["index", "routing", "allocation", "include"]
+          `taggedAt` ["index", "routing", "allocation", "include"]
           <|> routingAllocationExclude
-            `taggedAt` ["index", "routing", "allocation", "exclude"]
+          `taggedAt` ["index", "routing", "allocation", "exclude"]
           <|> routingAllocationRequire
-            `taggedAt` ["index", "routing", "allocation", "require"]
+          `taggedAt` ["index", "routing", "allocation", "require"]
           <|> routingAllocationEnable
-            `taggedAt` ["index", "routing", "allocation", "enable"]
+          `taggedAt` ["index", "routing", "allocation", "enable"]
           <|> routingAllocationShardsPerNode
-            `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
+          `taggedAt` ["index", "routing", "allocation", "total_shards_per_node"]
           <|> recoveryInitialShards
-            `taggedAt` ["index", "recovery", "initial_shards"]
+          `taggedAt` ["index", "recovery", "initial_shards"]
           <|> gcDeletes
-            `taggedAt` ["index", "gc_deletes"]
+          `taggedAt` ["index", "gc_deletes"]
           <|> ttlDisablePurge
-            `taggedAt` ["index", "ttl", "disable_purge"]
+          `taggedAt` ["index", "ttl", "disable_purge"]
           <|> translogFSType
-            `taggedAt` ["index", "translog", "fs", "type"]
+          `taggedAt` ["index", "translog", "fs", "type"]
           <|> compressionSetting
-            `taggedAt` ["index", "codec"]
+          `taggedAt` ["index", "codec"]
           <|> compoundFormat
-            `taggedAt` ["index", "compound_format"]
+          `taggedAt` ["index", "compound_format"]
           <|> compoundOnFlush
-            `taggedAt` ["index", "compound_on_flush"]
+          `taggedAt` ["index", "compound_on_flush"]
           <|> warmerEnabled
-            `taggedAt` ["index", "warmer", "enabled"]
+          `taggedAt` ["index", "warmer", "enabled"]
           <|> blocksReadOnly
-            `taggedAt` ["blocks", "read_only"]
+          `taggedAt` ["blocks", "read_only"]
           <|> blocksRead
-            `taggedAt` ["blocks", "read"]
+          `taggedAt` ["blocks", "read"]
           <|> blocksWrite
-            `taggedAt` ["blocks", "write"]
+          `taggedAt` ["blocks", "write"]
           <|> blocksMetaData
-            `taggedAt` ["blocks", "metadata"]
+          `taggedAt` ["blocks", "metadata"]
           <|> mappingTotalFieldsLimit
-            `taggedAt` ["index", "mapping", "total_fields", "limit"]
+          `taggedAt` ["index", "mapping", "total_fields", "limit"]
           <|> analysisSetting
-            `taggedAt` ["index", "analysis"]
+          `taggedAt` ["index", "analysis"]
           <|> unassignedNodeLeftDelayedTimeout
-            `taggedAt` ["index", "unassigned", "node_left", "delayed_timeout"]
+          `taggedAt` ["index", "unassigned", "node_left", "delayed_timeout"]
         where
           taggedAt :: (FromJSON a) => (a -> Parser b) -> [Key] -> Parser b
           taggedAt f ks = taggedAt' f (Object o) ks
@@ -568,8 +567,10 @@
 
 instance FromJSON CompoundFormat where
   parseJSON v =
-    CompoundFileFormat <$> parseJSON v
-      <|> MergeSegmentVsTotalIndex <$> parseJSON v
+    CompoundFileFormat
+      <$> parseJSON v
+        <|> MergeSegmentVsTotalIndex
+      <$> parseJSON v
 
 newtype NominalDiffTimeJSON = NominalDiffTimeJSON {ndtJSON :: NominalDiffTime}
 
@@ -590,14 +591,14 @@
   }
   deriving stock (Eq, Show)
 
-sSummaryIndexNameLens :: Lens' IndexSettingsSummary IndexName
-sSummaryIndexNameLens = lens sSummaryIndexName (\x y -> x {sSummaryIndexName = y})
+indexSettingsSummarySummaryIndexNameLens :: Lens' IndexSettingsSummary IndexName
+indexSettingsSummarySummaryIndexNameLens = lens sSummaryIndexName (\x y -> x {sSummaryIndexName = y})
 
-sSummaryFixedSettingsLens :: Lens' IndexSettingsSummary IndexSettings
-sSummaryFixedSettingsLens = lens sSummaryFixedSettings (\x y -> x {sSummaryFixedSettings = y})
+indexSettingsSummarySummaryFixedSettingsLens :: Lens' IndexSettingsSummary IndexSettings
+indexSettingsSummarySummaryFixedSettingsLens = lens sSummaryFixedSettings (\x y -> x {sSummaryFixedSettings = y})
 
-sSummaryUpdateableLens :: Lens' IndexSettingsSummary [UpdatableIndexSetting]
-sSummaryUpdateableLens = lens sSummaryUpdateable (\x y -> x {sSummaryUpdateable = y})
+indexSettingsSummarySummaryUpdateableLens :: Lens' IndexSettingsSummary [UpdatableIndexSetting]
+indexSettingsSummarySummaryUpdateableLens = lens sSummaryUpdateable (\x y -> x {sSummaryUpdateable = y})
 
 parseSettings :: Object -> Parser [UpdatableIndexSetting]
 parseSettings o = do
@@ -643,8 +644,8 @@
   }
   deriving stock (Eq, Show)
 
-fieldTypeLens :: Lens' FieldDefinition FieldType
-fieldTypeLens = lens fieldType (\x y -> x {fieldType = y})
+fieldDefinitionTypeLens :: Lens' FieldDefinition FieldType
+fieldDefinitionTypeLens = lens fieldType (\x y -> x {fieldType = y})
 
 -- | An 'IndexTemplate' defines a template that will automatically be
 --   applied to new indices created. The templates include both
@@ -673,14 +674,14 @@
       merge o Null = o
       merge _ _ = undefined
 
-templatePatternsLens :: Lens' IndexTemplate [IndexPattern]
-templatePatternsLens = lens templatePatterns (\x y -> x {templatePatterns = y})
+indexTemplatePatternsLens :: Lens' IndexTemplate [IndexPattern]
+indexTemplatePatternsLens = lens templatePatterns (\x y -> x {templatePatterns = y})
 
-templateSettingsLens :: Lens' IndexTemplate (Maybe IndexSettings)
-templateSettingsLens = lens templateSettings (\x y -> x {templateSettings = y})
+indexTemplateSettingsLens :: Lens' IndexTemplate (Maybe IndexSettings)
+indexTemplateSettingsLens = lens templateSettings (\x y -> x {templateSettings = y})
 
-templateMappingsLens :: Lens' IndexTemplate Value
-templateMappingsLens = lens templateMappings (\x y -> x {templateMappings = y})
+indexTemplateMappingsLens :: Lens' IndexTemplate Value
+indexTemplateMappingsLens = lens templateMappings (\x y -> x {templateMappings = y})
 
 data MappingField = MappingField
   { mappingFieldName :: FieldName,
@@ -691,8 +692,8 @@
 mappingFieldNameLens :: Lens' MappingField FieldName
 mappingFieldNameLens = lens mappingFieldName (\x y -> x {mappingFieldName = y})
 
-fieldDefinitionLens :: Lens' MappingField FieldDefinition
-fieldDefinitionLens = lens fieldDefinition (\x y -> x {fieldDefinition = y})
+mappingFieldDefinitionLens :: Lens' MappingField FieldDefinition
+mappingFieldDefinitionLens = lens fieldDefinition (\x y -> x {fieldDefinition = y})
 
 -- | Support for type reification of 'Mapping's is currently incomplete, for
 --   now the mapping API verbiage expects a 'ToJSON'able blob.
@@ -739,8 +740,8 @@
   }
   deriving stock (Eq, Show)
 
-srcIndexLens :: Lens' IndexAlias IndexName
-srcIndexLens = lens srcIndex (\x y -> x {srcIndex = y})
+indexAliasSrcIndexLens :: Lens' IndexAlias IndexName
+indexAliasSrcIndexLens = lens srcIndex (\x y -> x {srcIndex = y})
 
 indexAliasLens :: Lens' IndexAlias IndexAliasName
 indexAliasLens = lens indexAlias (\x y -> x {indexAlias = y})
@@ -756,11 +757,11 @@
   }
   deriving stock (Eq, Show)
 
-aliasCreateRoutingLens :: Lens' IndexAliasCreate (Maybe AliasRouting)
-aliasCreateRoutingLens = lens aliasCreateRouting (\x y -> x {aliasCreateRouting = y})
+indexAliasCreateRoutingLens :: Lens' IndexAliasCreate (Maybe AliasRouting)
+indexAliasCreateRoutingLens = lens aliasCreateRouting (\x y -> x {aliasCreateRouting = y})
 
-aliasCreateFilterLens :: Lens' IndexAliasCreate (Maybe Filter)
-aliasCreateFilterLens = lens aliasCreateFilter (\x y -> x {aliasCreateFilter = y})
+indexAliasCreateFilterLens :: Lens' IndexAliasCreate (Maybe Filter)
+indexAliasCreateFilterLens = lens aliasCreateFilter (\x y -> x {aliasCreateFilter = y})
 
 data AliasRouting
   = AllAliasRouting RoutingValue
@@ -879,11 +880,11 @@
   }
   deriving stock (Eq, Show)
 
-idsVersionControlLens :: Lens' IndexDocumentSettings VersionControl
-idsVersionControlLens = lens idsVersionControl (\x y -> x {idsVersionControl = y})
+indexDocumentSettingsVersionControlLens :: Lens' IndexDocumentSettings VersionControl
+indexDocumentSettingsVersionControlLens = lens idsVersionControl (\x y -> x {idsVersionControl = y})
 
-idsJoinRelationLens :: Lens' IndexDocumentSettings (Maybe JoinRelation)
-idsJoinRelationLens = lens idsJoinRelation (\x y -> x {idsJoinRelation = y})
+indexDocumentSettingsJoinRelationLens :: Lens' IndexDocumentSettings (Maybe JoinRelation)
+indexDocumentSettingsJoinRelationLens = lens idsJoinRelation (\x y -> x {idsJoinRelation = y})
 
 -- | Reasonable default settings. Chooses no version control and no parent.
 defaultIndexDocumentSettings :: IndexDocumentSettings
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Newtypes.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Newtypes.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Newtypes.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Newtypes.hs
@@ -169,6 +169,7 @@
 -- | 'MinimumMatch' controls how many should clauses in the bool query should
 --    match. Can be an absolute value (2) or a percentage (30%) or a
 --    combination of both.
+--    The current version only support absolute value.
 newtype MinimumMatch
   = MinimumMatch Int
   deriving newtype (Eq, Show, FromJSON, ToJSON)
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Nodes.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Nodes.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Nodes.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Nodes.hs
@@ -6,1540 +6,2889 @@
     BuildHash (..),
     CPUInfo (..),
     ClusterName (..),
-    EsAddress (..),
-    EsPassword (..),
-    EsUsername (..),
-    FullNodeId (..),
-    InitialShardCount (..),
-    JVMBufferPoolStats (..),
-    JVMGCCollector (..),
-    JVMGCStats (..),
-    JVMMemoryInfo (..),
-    JVMMemoryPool (..),
-    JVMPoolStats (..),
-    JVMVersion (..),
-    LoadAvgs (..),
-    MacAddress (..),
-    NetworkInterfaceName (..),
-    NodeAttrFilter (..),
-    NodeAttrName (..),
-    NodeBreakerStats (..),
-    NodeBreakersStats (..),
-    NodeDataPathStats (..),
-    NodeFSStats (..),
-    NodeFSTotalStats (..),
-    NodeHTTPInfo (..),
-    NodeHTTPStats (..),
-    NodeIndicesStats (..),
-    NodeInfo (..),
-    NodeJVMInfo (..),
-    NodeJVMStats (..),
-    NodeName (..),
-    NodeNetworkInfo (..),
-    NodeNetworkInterface (..),
-    NodeNetworkStats (..),
-    NodeOSInfo (..),
-    NodeOSStats (..),
-    NodePluginInfo (..),
-    NodeProcessInfo (..),
-    NodeProcessStats (..),
-    NodeSelection (..),
-    NodeSelector (..),
-    NodeStats (..),
-    NodeThreadPoolInfo (..),
-    NodeThreadPoolStats (..),
-    NodeTransportInfo (..),
-    NodeTransportStats (..),
-    NodesInfo (..),
-    NodesStats (..),
-    PID (..),
-    PluginName (..),
-    ShardResult (..),
-    ShardsResult (..),
-    ThreadPool (..),
-    ThreadPoolSize (..),
-    ThreadPoolType (..),
-    Version (..),
-    VersionNumber (..),
-
-    -- * Optics
-    nodeOSRefreshIntervalLens,
-    nodeOSNameLens,
-    nodeOSArchLens,
-    nodeOSVersionLens,
-    nodeOSAvailableProcessorsLens,
-    nodeOSAllocatedProcessorsLens,
-    cpuCacheSizeLens,
-    cpuCoresPerSocketLens,
-    cpuTotalSocketsLens,
-    cpuTotalCoresLens,
-    cpuMHZLens,
-    cpuModelLens,
-    cpuVendorLens,
-    nodeProcessMLockAllLens,
-    nodeProcessMaxFileDescriptorsLens,
-    nodeProcessIdLens,
-    nodeProcessRefreshIntervalLens,
-    srShardsLens,
-    shardTotalLens,
-    shardsSuccessfulLens,
-    shardsSkippedLens,
-    shardsFailedLens,
-    versionNumberLens,
-    versionBuildHashLens,
-    versionBuildDateLens,
-    versionBuildSnapshotLens,
-    versionLuceneVersionLens,
-  )
-where
-
-import Control.Monad.Except
-import qualified Data.Aeson.KeyMap as X
-import qualified Data.HashMap.Strict as HM
-import Data.Map.Strict (Map)
-import qualified Data.Text as T
-import qualified Data.Vector as V
-import qualified Data.Versions as Versions
-import Database.Bloodhound.Internal.Client.BHRequest
-import Database.Bloodhound.Internal.Utils.Imports
-import Database.Bloodhound.Internal.Utils.StringlyTyped
-import Database.Bloodhound.Internal.Versions.Common.Types.Newtypes
-import Database.Bloodhound.Internal.Versions.Common.Types.Units
-import GHC.Generics
-
-data NodeAttrFilter = NodeAttrFilter
-  { nodeAttrFilterName :: NodeAttrName,
-    nodeAttrFilterValues :: NonEmpty Text
-  }
-  deriving stock (Eq, Ord, Show)
-
-newtype NodeAttrName = NodeAttrName Text deriving stock (Eq, Ord, Show)
-
--- | 'NodeSelection' is used for most cluster APIs. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes here> for more details.
-data NodeSelection
-  = -- | Whatever node receives this request
-    LocalNode
-  | NodeList (NonEmpty NodeSelector)
-  | AllNodes
-  deriving stock (Eq, Show)
-
--- | An exact match or pattern to identify a node. Note that All of
--- these options support wildcarding, so your node name, server, attr
--- name can all contain * characters to be a fuzzy match.
-data NodeSelector
-  = NodeByName NodeName
-  | NodeByFullNodeId FullNodeId
-  | -- | e.g. 10.0.0.1 or even 10.0.0.*
-    NodeByHost Server
-  | -- | NodeAttrName can be a pattern, e.g. rack*. The value can too.
-    NodeByAttribute NodeAttrName Text
-  deriving stock (Eq, Show)
-
--- | Unique, automatically-generated name assigned to nodes that are
--- usually returned in node-oriented APIs.
-newtype FullNodeId = FullNodeId {fullNodeId :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
--- | A human-readable node name that is supplied by the user in the
--- node config or automatically generated by Elasticsearch.
-newtype NodeName = NodeName {nodeName :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
-newtype ClusterName = ClusterName {clusterName :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
--- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
-newtype EsUsername = EsUsername {esUsername :: Text} deriving (Read, Eq, Show)
-
--- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
-newtype EsPassword = EsPassword {esPassword :: Text} deriving (Read, Eq, Show)
-
-data NodesInfo = NodesInfo
-  { nodesInfo :: [NodeInfo],
-    nodesClusterName :: ClusterName
-  }
-  deriving stock (Eq, Show)
-
-data NodesStats = NodesStats
-  { nodesStats :: [NodeStats],
-    nodesStatsClusterName :: ClusterName
-  }
-  deriving stock (Eq, Show)
-
-data NodeStats = NodeStats
-  { nodeStatsName :: NodeName,
-    nodeStatsFullId :: FullNodeId,
-    nodeStatsBreakersStats :: Maybe NodeBreakersStats,
-    nodeStatsHTTP :: NodeHTTPStats,
-    nodeStatsTransport :: NodeTransportStats,
-    nodeStatsFS :: NodeFSStats,
-    nodeStatsNetwork :: Maybe NodeNetworkStats,
-    nodeStatsThreadPool :: Map Text NodeThreadPoolStats,
-    nodeStatsJVM :: NodeJVMStats,
-    nodeStatsProcess :: NodeProcessStats,
-    nodeStatsOS :: NodeOSStats,
-    nodeStatsIndices :: NodeIndicesStats
-  }
-  deriving stock (Eq, Show)
-
-data NodeBreakersStats = NodeBreakersStats
-  { nodeStatsParentBreaker :: NodeBreakerStats,
-    nodeStatsRequestBreaker :: NodeBreakerStats,
-    nodeStatsFieldDataBreaker :: NodeBreakerStats
-  }
-  deriving stock (Eq, Show)
-
-data NodeBreakerStats = NodeBreakerStats
-  { nodeBreakersTripped :: Int,
-    nodeBreakersOverhead :: Double,
-    nodeBreakersEstSize :: Bytes,
-    nodeBreakersLimitSize :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-data NodeHTTPStats = NodeHTTPStats
-  { nodeHTTPTotalOpened :: Int,
-    nodeHTTPCurrentOpen :: Int
-  }
-  deriving stock (Eq, Show)
-
-data NodeTransportStats = NodeTransportStats
-  { nodeTransportTXSize :: Bytes,
-    nodeTransportCount :: Int,
-    nodeTransportRXSize :: Bytes,
-    nodeTransportRXCount :: Int,
-    nodeTransportServerOpen :: Int
-  }
-  deriving stock (Eq, Show)
-
-data NodeFSStats = NodeFSStats
-  { nodeFSDataPaths :: [NodeDataPathStats],
-    nodeFSTotal :: NodeFSTotalStats,
-    nodeFSTimestamp :: UTCTime
-  }
-  deriving stock (Eq, Show)
-
-data NodeDataPathStats = NodeDataPathStats
-  { nodeDataPathDiskServiceTime :: Maybe Double,
-    nodeDataPathDiskQueue :: Maybe Double,
-    nodeDataPathIOSize :: Maybe Bytes,
-    nodeDataPathWriteSize :: Maybe Bytes,
-    nodeDataPathReadSize :: Maybe Bytes,
-    nodeDataPathIOOps :: Maybe Int,
-    nodeDataPathWrites :: Maybe Int,
-    nodeDataPathReads :: Maybe Int,
-    nodeDataPathAvailable :: Bytes,
-    nodeDataPathFree :: Bytes,
-    nodeDataPathTotal :: Bytes,
-    nodeDataPathType :: Maybe Text,
-    nodeDataPathDevice :: Maybe Text,
-    nodeDataPathMount :: Text,
-    nodeDataPathPath :: Text
-  }
-  deriving stock (Eq, Show)
-
-data NodeFSTotalStats = NodeFSTotalStats
-  { nodeFSTotalDiskServiceTime :: Maybe Double,
-    nodeFSTotalDiskQueue :: Maybe Double,
-    nodeFSTotalIOSize :: Maybe Bytes,
-    nodeFSTotalWriteSize :: Maybe Bytes,
-    nodeFSTotalReadSize :: Maybe Bytes,
-    nodeFSTotalIOOps :: Maybe Int,
-    nodeFSTotalWrites :: Maybe Int,
-    nodeFSTotalReads :: Maybe Int,
-    nodeFSTotalAvailable :: Bytes,
-    nodeFSTotalFree :: Bytes,
-    nodeFSTotalTotal :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-data NodeNetworkStats = NodeNetworkStats
-  { nodeNetTCPOutRSTs :: Int,
-    nodeNetTCPInErrs :: Int,
-    nodeNetTCPAttemptFails :: Int,
-    nodeNetTCPEstabResets :: Int,
-    nodeNetTCPRetransSegs :: Int,
-    nodeNetTCPOutSegs :: Int,
-    nodeNetTCPInSegs :: Int,
-    nodeNetTCPCurrEstab :: Int,
-    nodeNetTCPPassiveOpens :: Int,
-    nodeNetTCPActiveOpens :: Int
-  }
-  deriving stock (Eq, Show)
-
-data NodeThreadPoolStats = NodeThreadPoolStats
-  { nodeThreadPoolCompleted :: Int,
-    nodeThreadPoolLargest :: Int,
-    nodeThreadPoolRejected :: Int,
-    nodeThreadPoolActive :: Int,
-    nodeThreadPoolQueue :: Int,
-    nodeThreadPoolThreads :: Int
-  }
-  deriving stock (Eq, Show)
-
-data NodeJVMStats = NodeJVMStats
-  { nodeJVMStatsMappedBufferPool :: JVMBufferPoolStats,
-    nodeJVMStatsDirectBufferPool :: JVMBufferPoolStats,
-    nodeJVMStatsGCOldCollector :: JVMGCStats,
-    nodeJVMStatsGCYoungCollector :: JVMGCStats,
-    nodeJVMStatsPeakThreadsCount :: Int,
-    nodeJVMStatsThreadsCount :: Int,
-    nodeJVMStatsOldPool :: JVMPoolStats,
-    nodeJVMStatsSurvivorPool :: JVMPoolStats,
-    nodeJVMStatsYoungPool :: JVMPoolStats,
-    nodeJVMStatsNonHeapCommitted :: Bytes,
-    nodeJVMStatsNonHeapUsed :: Bytes,
-    nodeJVMStatsHeapMax :: Bytes,
-    nodeJVMStatsHeapCommitted :: Bytes,
-    nodeJVMStatsHeapUsedPercent :: Int,
-    nodeJVMStatsHeapUsed :: Bytes,
-    nodeJVMStatsUptime :: NominalDiffTime,
-    nodeJVMStatsTimestamp :: UTCTime
-  }
-  deriving stock (Eq, Show)
-
-data JVMBufferPoolStats = JVMBufferPoolStats
-  { jvmBufferPoolStatsTotalCapacity :: Bytes,
-    jvmBufferPoolStatsUsed :: Bytes,
-    jvmBufferPoolStatsCount :: Int
-  }
-  deriving stock (Eq, Show)
-
-data JVMGCStats = JVMGCStats
-  { jvmGCStatsCollectionTime :: NominalDiffTime,
-    jvmGCStatsCollectionCount :: Int
-  }
-  deriving stock (Eq, Show)
-
-data JVMPoolStats = JVMPoolStats
-  { jvmPoolStatsPeakMax :: Bytes,
-    jvmPoolStatsPeakUsed :: Bytes,
-    jvmPoolStatsMax :: Bytes,
-    jvmPoolStatsUsed :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-data NodeProcessStats = NodeProcessStats
-  { nodeProcessTimestamp :: UTCTime,
-    nodeProcessOpenFDs :: Int,
-    nodeProcessMaxFDs :: Int,
-    nodeProcessCPUPercent :: Int,
-    nodeProcessCPUTotal :: NominalDiffTime,
-    nodeProcessMemTotalVirtual :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-data NodeOSStats = NodeOSStats
-  { nodeOSTimestamp :: UTCTime,
-    nodeOSCPUPercent :: Int,
-    nodeOSLoad :: Maybe LoadAvgs,
-    nodeOSMemTotal :: Bytes,
-    nodeOSMemFree :: Bytes,
-    nodeOSMemFreePercent :: Int,
-    nodeOSMemUsed :: Bytes,
-    nodeOSMemUsedPercent :: Int,
-    nodeOSSwapTotal :: Bytes,
-    nodeOSSwapFree :: Bytes,
-    nodeOSSwapUsed :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-data LoadAvgs = LoadAvgs
-  { loadAvg1Min :: Double,
-    loadAvg5Min :: Double,
-    loadAvg15Min :: Double
-  }
-  deriving stock (Eq, Show)
-
-data NodeIndicesStats = NodeIndicesStats
-  { nodeIndicesStatsRecoveryThrottleTime :: Maybe NominalDiffTime,
-    nodeIndicesStatsRecoveryCurrentAsTarget :: Maybe Int,
-    nodeIndicesStatsRecoveryCurrentAsSource :: Maybe Int,
-    nodeIndicesStatsQueryCacheMisses :: Maybe Int,
-    nodeIndicesStatsQueryCacheHits :: Maybe Int,
-    nodeIndicesStatsQueryCacheEvictions :: Maybe Int,
-    nodeIndicesStatsQueryCacheSize :: Maybe Bytes,
-    nodeIndicesStatsSuggestCurrent :: Maybe Int,
-    nodeIndicesStatsSuggestTime :: Maybe NominalDiffTime,
-    nodeIndicesStatsSuggestTotal :: Maybe Int,
-    nodeIndicesStatsTranslogSize :: Bytes,
-    nodeIndicesStatsTranslogOps :: Int,
-    nodeIndicesStatsSegFixedBitSetMemory :: Maybe Bytes,
-    nodeIndicesStatsSegVersionMapMemory :: Bytes,
-    nodeIndicesStatsSegIndexWriterMaxMemory :: Maybe Bytes,
-    nodeIndicesStatsSegIndexWriterMemory :: Bytes,
-    nodeIndicesStatsSegMemory :: Bytes,
-    nodeIndicesStatsSegCount :: Int,
-    nodeIndicesStatsCompletionSize :: Bytes,
-    nodeIndicesStatsPercolateQueries :: Maybe Int,
-    nodeIndicesStatsPercolateMemory :: Maybe Bytes,
-    nodeIndicesStatsPercolateCurrent :: Maybe Int,
-    nodeIndicesStatsPercolateTime :: Maybe NominalDiffTime,
-    nodeIndicesStatsPercolateTotal :: Maybe Int,
-    nodeIndicesStatsFieldDataEvictions :: Int,
-    nodeIndicesStatsFieldDataMemory :: Bytes,
-    nodeIndicesStatsWarmerTotalTime :: NominalDiffTime,
-    nodeIndicesStatsWarmerTotal :: Int,
-    nodeIndicesStatsWarmerCurrent :: Int,
-    nodeIndicesStatsFlushTotalTime :: NominalDiffTime,
-    nodeIndicesStatsFlushTotal :: Int,
-    nodeIndicesStatsRefreshTotalTime :: NominalDiffTime,
-    nodeIndicesStatsRefreshTotal :: Int,
-    nodeIndicesStatsMergesTotalSize :: Bytes,
-    nodeIndicesStatsMergesTotalDocs :: Int,
-    nodeIndicesStatsMergesTotalTime :: NominalDiffTime,
-    nodeIndicesStatsMergesTotal :: Int,
-    nodeIndicesStatsMergesCurrentSize :: Bytes,
-    nodeIndicesStatsMergesCurrentDocs :: Int,
-    nodeIndicesStatsMergesCurrent :: Int,
-    nodeIndicesStatsSearchFetchCurrent :: Int,
-    nodeIndicesStatsSearchFetchTime :: NominalDiffTime,
-    nodeIndicesStatsSearchFetchTotal :: Int,
-    nodeIndicesStatsSearchQueryCurrent :: Int,
-    nodeIndicesStatsSearchQueryTime :: NominalDiffTime,
-    nodeIndicesStatsSearchQueryTotal :: Int,
-    nodeIndicesStatsSearchOpenContexts :: Int,
-    nodeIndicesStatsGetCurrent :: Int,
-    nodeIndicesStatsGetMissingTime :: NominalDiffTime,
-    nodeIndicesStatsGetMissingTotal :: Int,
-    nodeIndicesStatsGetExistsTime :: NominalDiffTime,
-    nodeIndicesStatsGetExistsTotal :: Int,
-    nodeIndicesStatsGetTime :: NominalDiffTime,
-    nodeIndicesStatsGetTotal :: Int,
-    nodeIndicesStatsIndexingThrottleTime :: Maybe NominalDiffTime,
-    nodeIndicesStatsIndexingIsThrottled :: Maybe Bool,
-    nodeIndicesStatsIndexingNoopUpdateTotal :: Maybe Int,
-    nodeIndicesStatsIndexingDeleteCurrent :: Int,
-    nodeIndicesStatsIndexingDeleteTime :: NominalDiffTime,
-    nodeIndicesStatsIndexingDeleteTotal :: Int,
-    nodeIndicesStatsIndexingIndexCurrent :: Int,
-    nodeIndicesStatsIndexingIndexTime :: NominalDiffTime,
-    nodeIndicesStatsIndexingTotal :: Int,
-    nodeIndicesStatsStoreThrottleTime :: Maybe NominalDiffTime,
-    nodeIndicesStatsStoreSize :: Bytes,
-    nodeIndicesStatsDocsDeleted :: Int,
-    nodeIndicesStatsDocsCount :: Int
-  }
-  deriving stock (Eq, Show)
-
--- | A quirky address format used throughout Elasticsearch. An example
--- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
--- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
-newtype EsAddress = EsAddress {esAddress :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
--- | Typically a 7 character hex string.
-newtype BuildHash = BuildHash {buildHash :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON, ToJSON)
-
-newtype PluginName = PluginName {pluginName :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
-data NodeInfo = NodeInfo
-  { nodeInfoHTTPAddress :: Maybe EsAddress,
-    nodeInfoBuild :: BuildHash,
-    nodeInfoESVersion :: VersionNumber,
-    nodeInfoIP :: Server,
-    nodeInfoHost :: Server,
-    nodeInfoTransportAddress :: EsAddress,
-    nodeInfoName :: NodeName,
-    nodeInfoFullId :: FullNodeId,
-    nodeInfoPlugins :: [NodePluginInfo],
-    nodeInfoHTTP :: NodeHTTPInfo,
-    nodeInfoTransport :: NodeTransportInfo,
-    nodeInfoNetwork :: Maybe NodeNetworkInfo,
-    nodeInfoThreadPool :: Map Text NodeThreadPoolInfo,
-    nodeInfoJVM :: NodeJVMInfo,
-    nodeInfoProcess :: NodeProcessInfo,
-    nodeInfoOS :: NodeOSInfo,
-    -- | The members of the settings objects are not consistent,
-    -- dependent on plugins, etc.
-    nodeInfoSettings :: Object
-  }
-  deriving stock (Eq, Show)
-
-data NodePluginInfo = NodePluginInfo
-  { -- | Is this a site plugin?
-    nodePluginSite :: Maybe Bool,
-    -- | Is this plugin running on the JVM
-    nodePluginJVM :: Maybe Bool,
-    nodePluginDescription :: Text,
-    nodePluginVersion :: MaybeNA VersionNumber,
-    nodePluginName :: PluginName
-  }
-  deriving stock (Eq, Show)
-
-data NodeHTTPInfo = NodeHTTPInfo
-  { nodeHTTPMaxContentLength :: Bytes,
-    nodeHTTPpublishAddress :: EsAddress,
-    nodeHTTPbound_address :: [EsAddress]
-  }
-  deriving stock (Eq, Show)
-
-data NodeTransportInfo = NodeTransportInfo
-  { nodeTransportProfiles :: [BoundTransportAddress],
-    nodeTransportPublishAddress :: EsAddress,
-    nodeTransportBoundAddress :: [EsAddress]
-  }
-  deriving stock (Eq, Show)
-
-data BoundTransportAddress = BoundTransportAddress
-  { publishAddress :: EsAddress,
-    boundAddress :: [EsAddress]
-  }
-  deriving stock (Eq, Show)
-
-data NodeNetworkInfo = NodeNetworkInfo
-  { nodeNetworkPrimaryInterface :: NodeNetworkInterface,
-    nodeNetworkRefreshInterval :: NominalDiffTime
-  }
-  deriving stock (Eq, Show)
-
-newtype MacAddress = MacAddress {macAddress :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
-newtype NetworkInterfaceName = NetworkInterfaceName {networkInterfaceName :: Text}
-  deriving newtype (Eq, Ord, Show, FromJSON)
-
-data NodeNetworkInterface = NodeNetworkInterface
-  { nodeNetIfaceMacAddress :: MacAddress,
-    nodeNetIfaceName :: NetworkInterfaceName,
-    nodeNetIfaceAddress :: Server
-  }
-  deriving stock (Eq, Show)
-
-data ThreadPool = ThreadPool
-  { nodeThreadPoolName :: Text,
-    nodeThreadPoolInfo :: NodeThreadPoolInfo
-  }
-  deriving stock (Eq, Show)
-
-data NodeThreadPoolInfo = NodeThreadPoolInfo
-  { nodeThreadPoolQueueSize :: ThreadPoolSize,
-    nodeThreadPoolKeepalive :: Maybe NominalDiffTime,
-    nodeThreadPoolMin :: Maybe Int,
-    nodeThreadPoolMax :: Maybe Int,
-    nodeThreadPoolType :: ThreadPoolType
-  }
-  deriving stock (Eq, Show)
-
-data ThreadPoolSize
-  = ThreadPoolBounded Int
-  | ThreadPoolUnbounded
-  deriving stock (Eq, Show)
-
-data ThreadPoolType
-  = ThreadPoolScaling
-  | ThreadPoolFixed
-  | ThreadPoolCached
-  | ThreadPoolFixedAutoQueueSize
-  deriving stock (Eq, Show)
-
-data NodeJVMInfo = NodeJVMInfo
-  { nodeJVMInfoMemoryPools :: [JVMMemoryPool],
-    nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector],
-    nodeJVMInfoMemoryInfo :: JVMMemoryInfo,
-    nodeJVMInfoStartTime :: UTCTime,
-    nodeJVMInfoVMVendor :: Text,
-    -- | JVM doesn't seme to follow normal version conventions
-    nodeJVMVMVersion :: VersionNumber,
-    nodeJVMVMName :: Text,
-    nodeJVMVersion :: JVMVersion,
-    nodeJVMPID :: PID
-  }
-  deriving stock (Eq, Show)
-
--- | We cannot parse JVM version numbers and we're not going to try.
-newtype JVMVersion = JVMVersion {unJVMVersion :: Text}
-  deriving stock (Eq, Show)
-
-instance FromJSON JVMVersion where
-  parseJSON = withText "JVMVersion" (pure . JVMVersion)
-
-data JVMMemoryInfo = JVMMemoryInfo
-  { jvmMemoryInfoDirectMax :: Bytes,
-    jvmMemoryInfoNonHeapMax :: Bytes,
-    jvmMemoryInfoNonHeapInit :: Bytes,
-    jvmMemoryInfoHeapMax :: Bytes,
-    jvmMemoryInfoHeapInit :: Bytes
-  }
-  deriving stock (Eq, Show)
-
-newtype JVMMemoryPool = JVMMemoryPool
-  { jvmMemoryPool :: Text
-  }
-  deriving newtype (Eq, Show, FromJSON)
-
-newtype JVMGCCollector = JVMGCCollector
-  { jvmGCCollector :: Text
-  }
-  deriving newtype (Eq, Show, FromJSON)
-
-newtype PID = PID
-  { pid :: Int
-  }
-  deriving newtype (Eq, Show, FromJSON)
-
-data NodeOSInfo = NodeOSInfo
-  { nodeOSRefreshInterval :: NominalDiffTime,
-    nodeOSName :: Text,
-    nodeOSArch :: Text,
-    nodeOSVersion :: Text, -- semver breaks on "5.10.60.1-microsoft-standard-WSL2"
-    nodeOSAvailableProcessors :: Int,
-    nodeOSAllocatedProcessors :: Int
-  }
-  deriving stock (Eq, Show)
-
-nodeOSRefreshIntervalLens :: Lens' NodeOSInfo NominalDiffTime
-nodeOSRefreshIntervalLens = lens nodeOSRefreshInterval (\x y -> x {nodeOSRefreshInterval = y})
-
-nodeOSNameLens :: Lens' NodeOSInfo Text
-nodeOSNameLens = lens nodeOSName (\x y -> x {nodeOSName = y})
-
-nodeOSArchLens :: Lens' NodeOSInfo Text
-nodeOSArchLens = lens nodeOSArch (\x y -> x {nodeOSArch = y})
-
-nodeOSVersionLens :: Lens' NodeOSInfo Text
-nodeOSVersionLens = lens nodeOSVersion (\x y -> x {nodeOSVersion = y})
-
-nodeOSAvailableProcessorsLens :: Lens' NodeOSInfo Int
-nodeOSAvailableProcessorsLens = lens nodeOSAvailableProcessors (\x y -> x {nodeOSAvailableProcessors = y})
-
-nodeOSAllocatedProcessorsLens :: Lens' NodeOSInfo Int
-nodeOSAllocatedProcessorsLens = lens nodeOSAllocatedProcessors (\x y -> x {nodeOSAllocatedProcessors = y})
-
-data CPUInfo = CPUInfo
-  { cpuCacheSize :: Bytes,
-    cpuCoresPerSocket :: Int,
-    cpuTotalSockets :: Int,
-    cpuTotalCores :: Int,
-    cpuMHZ :: Int,
-    cpuModel :: Text,
-    cpuVendor :: Text
-  }
-  deriving stock (Eq, Show)
-
-cpuCacheSizeLens :: Lens' CPUInfo Bytes
-cpuCacheSizeLens = lens cpuCacheSize (\x y -> x {cpuCacheSize = y})
-
-cpuCoresPerSocketLens :: Lens' CPUInfo Int
-cpuCoresPerSocketLens = lens cpuCoresPerSocket (\x y -> x {cpuCoresPerSocket = y})
-
-cpuTotalSocketsLens :: Lens' CPUInfo Int
-cpuTotalSocketsLens = lens cpuTotalSockets (\x y -> x {cpuTotalSockets = y})
-
-cpuTotalCoresLens :: Lens' CPUInfo Int
-cpuTotalCoresLens = lens cpuTotalCores (\x y -> x {cpuTotalCores = y})
-
-cpuMHZLens :: Lens' CPUInfo Int
-cpuMHZLens = lens cpuMHZ (\x y -> x {cpuMHZ = y})
-
-cpuModelLens :: Lens' CPUInfo Text
-cpuModelLens = lens cpuModel (\x y -> x {cpuModel = y})
-
-cpuVendorLens :: Lens' CPUInfo Text
-cpuVendorLens = lens cpuVendor (\x y -> x {cpuVendor = y})
-
-data NodeProcessInfo = NodeProcessInfo
-  { -- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
-    nodeProcessMLockAll :: Bool,
-    nodeProcessMaxFileDescriptors :: Maybe Int,
-    nodeProcessId :: PID,
-    nodeProcessRefreshInterval :: NominalDiffTime
-  }
-  deriving stock (Eq, Show)
-
-nodeProcessMLockAllLens :: Lens' NodeProcessInfo Bool
-nodeProcessMLockAllLens = lens nodeProcessMLockAll (\x y -> x {nodeProcessMLockAll = y})
-
-nodeProcessMaxFileDescriptorsLens :: Lens' NodeProcessInfo (Maybe Int)
-nodeProcessMaxFileDescriptorsLens = lens nodeProcessMaxFileDescriptors (\x y -> x {nodeProcessMaxFileDescriptors = y})
-
-nodeProcessIdLens :: Lens' NodeProcessInfo PID
-nodeProcessIdLens = lens nodeProcessId (\x y -> x {nodeProcessId = y})
-
-nodeProcessRefreshIntervalLens :: Lens' NodeProcessInfo NominalDiffTime
-nodeProcessRefreshIntervalLens = lens nodeProcessRefreshInterval (\x y -> x {nodeProcessRefreshInterval = y})
-
-instance FromJSON NodesInfo where
-  parseJSON = withObject "NodesInfo" parse
-    where
-      parse o = do
-        nodes <- o .: "nodes"
-        infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
-          node <- parseJSON v
-          parseNodeInfo (FullNodeId fullNID) node
-        cn <- o .: "cluster_name"
-        return (NodesInfo infos cn)
-
-instance FromJSON NodesStats where
-  parseJSON = withObject "NodesStats" parse
-    where
-      parse o = do
-        nodes <- o .: "nodes"
-        stats <- forM (HM.toList nodes) $ \(fullNID, v) -> do
-          node <- parseJSON v
-          parseNodeStats (FullNodeId fullNID) node
-        cn <- o .: "cluster_name"
-        return (NodesStats stats cn)
-
-instance FromJSON NodeBreakerStats where
-  parseJSON = withObject "NodeBreakerStats" parse
-    where
-      parse o =
-        NodeBreakerStats
-          <$> o
-            .: "tripped"
-          <*> o
-            .: "overhead"
-          <*> o
-            .: "estimated_size_in_bytes"
-          <*> o
-            .: "limit_size_in_bytes"
-
-instance FromJSON NodeHTTPStats where
-  parseJSON = withObject "NodeHTTPStats" parse
-    where
-      parse o =
-        NodeHTTPStats
-          <$> o
-            .: "total_opened"
-          <*> o
-            .: "current_open"
-
-instance FromJSON NodeTransportStats where
-  parseJSON = withObject "NodeTransportStats" parse
-    where
-      parse o =
-        NodeTransportStats
-          <$> o
-            .: "tx_size_in_bytes"
-          <*> o
-            .: "tx_count"
-          <*> o
-            .: "rx_size_in_bytes"
-          <*> o
-            .: "rx_count"
-          <*> o
-            .: "server_open"
-
-instance FromJSON NodeFSStats where
-  parseJSON = withObject "NodeFSStats" parse
-    where
-      parse o =
-        NodeFSStats
-          <$> o
-            .: "data"
-          <*> o
-            .: "total"
-          <*> (posixMS <$> o .: "timestamp")
-
-instance FromJSON NodeDataPathStats where
-  parseJSON = withObject "NodeDataPathStats" parse
-    where
-      parse o =
-        NodeDataPathStats
-          <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
-          <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
-          <*> o
-            .:? "disk_io_size_in_bytes"
-          <*> o
-            .:? "disk_write_size_in_bytes"
-          <*> o
-            .:? "disk_read_size_in_bytes"
-          <*> o
-            .:? "disk_io_op"
-          <*> o
-            .:? "disk_writes"
-          <*> o
-            .:? "disk_reads"
-          <*> o
-            .: "available_in_bytes"
-          <*> o
-            .: "free_in_bytes"
-          <*> o
-            .: "total_in_bytes"
-          <*> o
-            .:? "type"
-          <*> o
-            .:? "dev"
-          <*> o
-            .: "mount"
-          <*> o
-            .: "path"
-
-instance FromJSON NodeFSTotalStats where
-  parseJSON = withObject "NodeFSTotalStats" parse
-    where
-      parse o =
-        NodeFSTotalStats
-          <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
-          <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
-          <*> o
-            .:? "disk_io_size_in_bytes"
-          <*> o
-            .:? "disk_write_size_in_bytes"
-          <*> o
-            .:? "disk_read_size_in_bytes"
-          <*> o
-            .:? "disk_io_op"
-          <*> o
-            .:? "disk_writes"
-          <*> o
-            .:? "disk_reads"
-          <*> o
-            .: "available_in_bytes"
-          <*> o
-            .: "free_in_bytes"
-          <*> o
-            .: "total_in_bytes"
-
-instance FromJSON NodeNetworkStats where
-  parseJSON = withObject "NodeNetworkStats" parse
-    where
-      parse o = do
-        tcp <- o .: "tcp"
-        NodeNetworkStats
-          <$> tcp
-            .: "out_rsts"
-          <*> tcp
-            .: "in_errs"
-          <*> tcp
-            .: "attempt_fails"
-          <*> tcp
-            .: "estab_resets"
-          <*> tcp
-            .: "retrans_segs"
-          <*> tcp
-            .: "out_segs"
-          <*> tcp
-            .: "in_segs"
-          <*> tcp
-            .: "curr_estab"
-          <*> tcp
-            .: "passive_opens"
-          <*> tcp
-            .: "active_opens"
-
-instance FromJSON NodeThreadPoolStats where
-  parseJSON = withObject "NodeThreadPoolStats" parse
-    where
-      parse o =
-        NodeThreadPoolStats
-          <$> o
-            .: "completed"
-          <*> o
-            .: "largest"
-          <*> o
-            .: "rejected"
-          <*> o
-            .: "active"
-          <*> o
-            .: "queue"
-          <*> o
-            .: "threads"
-
-instance FromJSON NodeJVMStats where
-  parseJSON = withObject "NodeJVMStats" parse
-    where
-      parse o = do
-        bufferPools <- o .: "buffer_pools"
-        mapped <- bufferPools .: "mapped"
-        direct <- bufferPools .: "direct"
-        gc <- o .: "gc"
-        collectors <- gc .: "collectors"
-        oldC <- collectors .: "old"
-        youngC <- collectors .: "young"
-        threads <- o .: "threads"
-        mem <- o .: "mem"
-        pools <- mem .: "pools"
-        oldM <- pools .: "old"
-        survivorM <- pools .: "survivor"
-        youngM <- pools .: "young"
-        NodeJVMStats
-          <$> pure mapped
-          <*> pure direct
-          <*> pure oldC
-          <*> pure youngC
-          <*> threads
-            .: "peak_count"
-          <*> threads
-            .: "count"
-          <*> pure oldM
-          <*> pure survivorM
-          <*> pure youngM
-          <*> mem
-            .: "non_heap_committed_in_bytes"
-          <*> mem
-            .: "non_heap_used_in_bytes"
-          <*> mem
-            .: "heap_max_in_bytes"
-          <*> mem
-            .: "heap_committed_in_bytes"
-          <*> mem
-            .: "heap_used_percent"
-          <*> mem
-            .: "heap_used_in_bytes"
-          <*> (unMS <$> o .: "uptime_in_millis")
-          <*> (posixMS <$> o .: "timestamp")
-
-instance FromJSON JVMBufferPoolStats where
-  parseJSON = withObject "JVMBufferPoolStats" parse
-    where
-      parse o =
-        JVMBufferPoolStats
-          <$> o
-            .: "total_capacity_in_bytes"
-          <*> o
-            .: "used_in_bytes"
-          <*> o
-            .: "count"
-
-instance FromJSON JVMGCStats where
-  parseJSON = withObject "JVMGCStats" parse
-    where
-      parse o =
-        JVMGCStats
-          <$> (unMS <$> o .: "collection_time_in_millis")
-          <*> o
-            .: "collection_count"
-
-instance FromJSON JVMPoolStats where
-  parseJSON = withObject "JVMPoolStats" parse
-    where
-      parse o =
-        JVMPoolStats
-          <$> o
-            .: "peak_max_in_bytes"
-          <*> o
-            .: "peak_used_in_bytes"
-          <*> o
-            .: "max_in_bytes"
-          <*> o
-            .: "used_in_bytes"
-
-instance FromJSON NodeProcessStats where
-  parseJSON = withObject "NodeProcessStats" parse
-    where
-      parse o = do
-        mem <- o .: "mem"
-        cpu <- o .: "cpu"
-        NodeProcessStats
-          <$> (posixMS <$> o .: "timestamp")
-          <*> o
-            .: "open_file_descriptors"
-          <*> o
-            .: "max_file_descriptors"
-          <*> cpu
-            .: "percent"
-          <*> (unMS <$> cpu .: "total_in_millis")
-          <*> mem
-            .: "total_virtual_in_bytes"
-
-instance FromJSON NodeOSStats where
-  parseJSON = withObject "NodeOSStats" parse
-    where
-      parse o = do
-        swap <- o .: "swap"
-        mem <- o .: "mem"
-        cpu <- o .: "cpu"
-        load <- o .:? "load_average"
-        NodeOSStats
-          <$> (posixMS <$> o .: "timestamp")
-          <*> cpu
-            .: "percent"
-          <*> pure load
-          <*> mem
-            .: "total_in_bytes"
-          <*> mem
-            .: "free_in_bytes"
-          <*> mem
-            .: "free_percent"
-          <*> mem
-            .: "used_in_bytes"
-          <*> mem
-            .: "used_percent"
-          <*> swap
-            .: "total_in_bytes"
-          <*> swap
-            .: "free_in_bytes"
-          <*> swap
-            .: "used_in_bytes"
-
-instance FromJSON LoadAvgs where
-  parseJSON = withArray "LoadAvgs" parse
-    where
-      parse v = case V.toList v of
-        [one, five, fifteen] ->
-          LoadAvgs
-            <$> parseJSON one
-            <*> parseJSON five
-            <*> parseJSON fifteen
-        _ -> fail "Expecting a triple of Doubles"
-
-instance FromJSON NodeIndicesStats where
-  parseJSON = withObject "NodeIndicesStats" parse
-    where
-      parse o = do
-        let (.::) mv k = case mv of
-              Just v -> Just <$> v .: k
-              Nothing -> pure Nothing
-        mRecovery <- o .:? "recovery"
-        mQueryCache <- o .:? "query_cache"
-        mSuggest <- o .:? "suggest"
-        translog <- o .: "translog"
-        segments <- o .: "segments"
-        completion <- o .: "completion"
-        mPercolate <- o .:? "percolate"
-        fielddata <- o .: "fielddata"
-        warmer <- o .: "warmer"
-        flush <- o .: "flush"
-        refresh <- o .: "refresh"
-        merges <- o .: "merges"
-        search <- o .: "search"
-        getStats <- o .: "get"
-        indexing <- o .: "indexing"
-        store <- o .: "store"
-        docs <- o .: "docs"
-        NodeIndicesStats
-          <$> (fmap unMS <$> mRecovery .:: "throttle_time_in_millis")
-          <*> mRecovery
-          .:: "current_as_target"
-          <*> mRecovery
-          .:: "current_as_source"
-          <*> mQueryCache
-          .:: "miss_count"
-          <*> mQueryCache
-          .:: "hit_count"
-          <*> mQueryCache
-          .:: "evictions"
-          <*> mQueryCache
-          .:: "memory_size_in_bytes"
-          <*> mSuggest
-          .:: "current"
-          <*> (fmap unMS <$> mSuggest .:: "time_in_millis")
-          <*> mSuggest
-          .:: "total"
-          <*> translog
-          .: "size_in_bytes"
-          <*> translog
-          .: "operations"
-          <*> segments
-          .:? "fixed_bit_set_memory_in_bytes"
-          <*> segments
-          .: "version_map_memory_in_bytes"
-          <*> segments
-          .:? "index_writer_max_memory_in_bytes"
-          <*> segments
-          .: "index_writer_memory_in_bytes"
-          <*> segments
-          .: "memory_in_bytes"
-          <*> segments
-          .: "count"
-          <*> completion
-          .: "size_in_bytes"
-          <*> mPercolate
-          .:: "queries"
-          <*> mPercolate
-          .:: "memory_size_in_bytes"
-          <*> mPercolate
-          .:: "current"
-          <*> (fmap unMS <$> mPercolate .:: "time_in_millis")
-          <*> mPercolate
-          .:: "total"
-          <*> fielddata
-          .: "evictions"
-          <*> fielddata
-          .: "memory_size_in_bytes"
-          <*> (unMS <$> warmer .: "total_time_in_millis")
-          <*> warmer
-          .: "total"
-          <*> warmer
-          .: "current"
-          <*> (unMS <$> flush .: "total_time_in_millis")
-          <*> flush
-          .: "total"
-          <*> (unMS <$> refresh .: "total_time_in_millis")
-          <*> refresh
-          .: "total"
-          <*> merges
-          .: "total_size_in_bytes"
-          <*> merges
-          .: "total_docs"
-          <*> (unMS <$> merges .: "total_time_in_millis")
-          <*> merges
-          .: "total"
-          <*> merges
-          .: "current_size_in_bytes"
-          <*> merges
-          .: "current_docs"
-          <*> merges
-          .: "current"
-          <*> search
-          .: "fetch_current"
-          <*> (unMS <$> search .: "fetch_time_in_millis")
-          <*> search
-          .: "fetch_total"
-          <*> search
-          .: "query_current"
-          <*> (unMS <$> search .: "query_time_in_millis")
-          <*> search
-          .: "query_total"
-          <*> search
-          .: "open_contexts"
-          <*> getStats
-          .: "current"
-          <*> (unMS <$> getStats .: "missing_time_in_millis")
-          <*> getStats
-          .: "missing_total"
-          <*> (unMS <$> getStats .: "exists_time_in_millis")
-          <*> getStats
-          .: "exists_total"
-          <*> (unMS <$> getStats .: "time_in_millis")
-          <*> getStats
-          .: "total"
-          <*> (fmap unMS <$> indexing .:? "throttle_time_in_millis")
-          <*> indexing
-          .:? "is_throttled"
-          <*> indexing
-          .:? "noop_update_total"
-          <*> indexing
-          .: "delete_current"
-          <*> (unMS <$> indexing .: "delete_time_in_millis")
-          <*> indexing
-          .: "delete_total"
-          <*> indexing
-          .: "index_current"
-          <*> (unMS <$> indexing .: "index_time_in_millis")
-          <*> indexing
-          .: "index_total"
-          <*> (fmap unMS <$> store .:? "throttle_time_in_millis")
-          <*> store
-          .: "size_in_bytes"
-          <*> docs
-          .: "deleted"
-          <*> docs
-          .: "count"
-
-instance FromJSON NodeBreakersStats where
-  parseJSON = withObject "NodeBreakersStats" parse
-    where
-      parse o =
-        NodeBreakersStats
-          <$> o
-            .: "parent"
-          <*> o
-            .: "request"
-          <*> o
-            .: "fielddata"
-
-parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
-parseNodeStats fnid o =
-  NodeStats
-    <$> o
-      .: "name"
-    <*> pure fnid
-    <*> o
-      .:? "breakers"
-    <*> o
-      .: "http"
-    <*> o
-      .: "transport"
-    <*> o
-      .: "fs"
-    <*> o
-      .:? "network"
-    <*> o
-      .: "thread_pool"
-    <*> o
-      .: "jvm"
-    <*> o
-      .: "process"
-    <*> o
-      .: "os"
-    <*> o
-      .: "indices"
-
-parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
-parseNodeInfo nid o =
-  NodeInfo
-    <$> o
-      .:? "http_address"
-    <*> o
-      .: "build_hash"
-    <*> o
-      .: "version"
-    <*> o
-      .: "ip"
-    <*> o
-      .: "host"
-    <*> o
-      .: "transport_address"
-    <*> o
-      .: "name"
-    <*> pure nid
-    <*> o
-      .: "plugins"
-    <*> o
-      .: "http"
-    <*> o
-      .: "transport"
-    <*> o
-      .:? "network"
-    <*> o
-      .: "thread_pool"
-    <*> o
-      .: "jvm"
-    <*> o
-      .: "process"
-    <*> o
-      .: "os"
-    <*> o
-      .: "settings"
-
-instance FromJSON NodePluginInfo where
-  parseJSON = withObject "NodePluginInfo" parse
-    where
-      parse o =
-        NodePluginInfo
-          <$> o
-            .:? "site"
-          <*> o
-            .:? "jvm"
-          <*> o
-            .: "description"
-          <*> o
-            .: "version"
-          <*> o
-            .: "name"
-
-instance FromJSON NodeHTTPInfo where
-  parseJSON = withObject "NodeHTTPInfo" parse
-    where
-      parse o =
-        NodeHTTPInfo
-          <$> o
-            .: "max_content_length_in_bytes"
-          <*> o
-            .: "publish_address"
-          <*> o
-            .: "bound_address"
-
-instance FromJSON BoundTransportAddress where
-  parseJSON = withObject "BoundTransportAddress" parse
-    where
-      parse o =
-        BoundTransportAddress
-          <$> o
-            .: "publish_address"
-          <*> o
-            .: "bound_address"
-
-instance FromJSON NodeOSInfo where
-  parseJSON = withObject "NodeOSInfo" parse
-    where
-      parse o =
-        NodeOSInfo
-          <$> (unMS <$> o .: "refresh_interval_in_millis")
-          <*> o
-            .: "name"
-          <*> o
-            .: "arch"
-          <*> o
-            .: "version"
-          <*> o
-            .: "available_processors"
-          <*> o
-            .: "allocated_processors"
-
-instance FromJSON CPUInfo where
-  parseJSON = withObject "CPUInfo" parse
-    where
-      parse o =
-        CPUInfo
-          <$> o
-            .: "cache_size_in_bytes"
-          <*> o
-            .: "cores_per_socket"
-          <*> o
-            .: "total_sockets"
-          <*> o
-            .: "total_cores"
-          <*> o
-            .: "mhz"
-          <*> o
-            .: "model"
-          <*> o
-            .: "vendor"
-
-instance FromJSON NodeProcessInfo where
-  parseJSON = withObject "NodeProcessInfo" parse
-    where
-      parse o =
-        NodeProcessInfo
-          <$> o
-            .: "mlockall"
-          <*> o
-            .:? "max_file_descriptors"
-          <*> o
-            .: "id"
-          <*> (unMS <$> o .: "refresh_interval_in_millis")
-
-instance FromJSON NodeJVMInfo where
-  parseJSON = withObject "NodeJVMInfo" parse
-    where
-      parse o =
-        NodeJVMInfo
-          <$> o
-            .: "memory_pools"
-          <*> o
-            .: "gc_collectors"
-          <*> o
-            .: "mem"
-          <*> (posixMS <$> o .: "start_time_in_millis")
-          <*> o
-            .: "vm_vendor"
-          <*> o
-            .: "vm_version"
-          <*> o
-            .: "vm_name"
-          <*> o
-            .: "version"
-          <*> o
-            .: "pid"
-
-instance FromJSON JVMMemoryInfo where
-  parseJSON = withObject "JVMMemoryInfo" parse
-    where
-      parse o =
-        JVMMemoryInfo
-          <$> o
-            .: "direct_max_in_bytes"
-          <*> o
-            .: "non_heap_max_in_bytes"
-          <*> o
-            .: "non_heap_init_in_bytes"
-          <*> o
-            .: "heap_max_in_bytes"
-          <*> o
-            .: "heap_init_in_bytes"
-
-instance FromJSON NodeThreadPoolInfo where
-  parseJSON = withObject "NodeThreadPoolInfo" parse
-    where
-      parse o = do
-        ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
-        NodeThreadPoolInfo
-          <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
-          <*> pure ka
-          <*> o
-            .:? "min"
-          <*> o
-            .:? "max"
-          <*> o
-            .: "type"
-
-instance FromJSON ThreadPoolSize where
-  parseJSON v = parseAsNumber v <|> parseAsString v
-    where
-      parseAsNumber = parseAsInt <=< parseJSON
-      parseAsInt (-1) = return ThreadPoolUnbounded
-      parseAsInt n
-        | n >= 0 = return (ThreadPoolBounded n)
-        | otherwise = fail "Thread pool size must be >= -1."
-      parseAsString = withText "ThreadPoolSize" $ \t ->
-        case first (readMay . T.unpack) (T.span isNumber t) of
-          (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
-          (Just n, "") -> return (ThreadPoolBounded n)
-          _ -> fail ("Invalid thread pool size " <> T.unpack t)
-
-instance FromJSON ThreadPoolType where
-  parseJSON = withText "ThreadPoolType" parse
-    where
-      parse "scaling" = return ThreadPoolScaling
-      parse "fixed" = return ThreadPoolFixed
-      parse "cached" = return ThreadPoolCached
-      parse "fixed_auto_queue_size" = return ThreadPoolFixedAutoQueueSize
-      parse e = fail ("Unexpected thread pool type" <> T.unpack e)
-
-instance FromJSON NodeTransportInfo where
-  parseJSON = withObject "NodeTransportInfo" parse
-    where
-      parse o =
-        NodeTransportInfo
-          <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
-          <*> o
-            .: "publish_address"
-          <*> o
-            .: "bound_address"
-      parseProfiles (Object o) | X.null o = return []
-      parseProfiles v@(Array _) = parseJSON v
-      parseProfiles Null = return []
-      parseProfiles _ = fail "Could not parse profiles"
-
-instance FromJSON NodeNetworkInfo where
-  parseJSON = withObject "NodeNetworkInfo" parse
-    where
-      parse o =
-        NodeNetworkInfo
-          <$> o
-            .: "primary_interface"
-          <*> (unMS <$> o .: "refresh_interval_in_millis")
-
-instance FromJSON NodeNetworkInterface where
-  parseJSON = withObject "NodeNetworkInterface" parse
-    where
-      parse o =
-        NodeNetworkInterface
-          <$> o
-            .: "mac_address"
-          <*> o
-            .: "name"
-          <*> o
-            .: "address"
-
-data InitialShardCount
-  = QuorumShards
-  | QuorumMinus1Shards
-  | FullShards
-  | FullMinus1Shards
-  | ExplicitShards Int
-  deriving stock (Eq, Show, Generic)
-
-instance FromJSON InitialShardCount where
-  parseJSON v =
-    withText "InitialShardCount" parseText v
-      <|> ExplicitShards <$> parseJSON v
-    where
-      parseText "quorum" = pure QuorumShards
-      parseText "quorum-1" = pure QuorumMinus1Shards
-      parseText "full" = pure FullShards
-      parseText "full-1" = pure FullMinus1Shards
-      parseText _ = mzero
-
-instance ToJSON InitialShardCount where
-  toJSON QuorumShards = String "quorum"
-  toJSON QuorumMinus1Shards = String "quorum-1"
-  toJSON FullShards = String "full"
-  toJSON FullMinus1Shards = String "full-1"
-  toJSON (ExplicitShards x) = toJSON x
-
-newtype ShardsResult = ShardsResult
-  { srShards :: ShardResult
-  }
-  deriving stock (Eq, Show)
-
-instance FromJSON ShardsResult where
-  parseJSON =
-    withObject "ShardsResult" $ \v ->
-      ShardsResult
-        <$> v
-          .: "_shards"
-
-srShardsLens :: Lens' ShardsResult ShardResult
-srShardsLens = lens srShards (\x y -> x {srShards = y})
-
-data ShardResult = ShardResult
-  { shardTotal :: Int,
-    shardsSuccessful :: Int,
-    shardsSkipped :: Int,
-    shardsFailed :: Int
-  }
-  deriving stock (Eq, Show)
-
-instance FromJSON ShardResult where
-  parseJSON =
-    withObject "ShardResult" $ \v ->
-      ShardResult
-        <$> v .:? "total" .!= 0
-        <*> v .:? "successful" .!= 0
-        <*> v .:? "skipped" .!= 0
-        <*> v .:? "failed" .!= 0
-
-instance ToJSON ShardResult where
-  toJSON ShardResult {..} =
-    object
-      [ "total" .= shardTotal,
-        "successful" .= shardsSuccessful,
-        "skipped" .= shardsSkipped,
-        "failed" .= shardsFailed
-      ]
-
-shardTotalLens :: Lens' ShardResult Int
-shardTotalLens = lens shardTotal (\x y -> x {shardTotal = y})
-
-shardsSuccessfulLens :: Lens' ShardResult Int
-shardsSuccessfulLens = lens shardsSuccessful (\x y -> x {shardsSuccessful = y})
-
-shardsSkippedLens :: Lens' ShardResult Int
-shardsSkippedLens = lens shardsSkipped (\x y -> x {shardsSkipped = y})
-
-shardsFailedLens :: Lens' ShardResult Int
-shardsFailedLens = lens shardsFailed (\x y -> x {shardsFailed = y})
-
--- | 'Version' is embedded in 'Status'
-data Version = Version
-  { number :: VersionNumber,
-    build_hash :: BuildHash,
-    build_date :: UTCTime,
-    build_snapshot :: Bool,
-    lucene_version :: VersionNumber
-  }
-  deriving stock (Eq, Show, Generic)
-
-instance ToJSON Version where
-  toJSON Version {..} =
-    object
-      [ "number" .= number,
-        "build_hash" .= build_hash,
-        "build_date" .= build_date,
-        "build_snapshot" .= build_snapshot,
-        "lucene_version" .= lucene_version
-      ]
-
-instance FromJSON Version where
-  parseJSON = withObject "Version" parse
-    where
-      parse o =
-        Version
-          <$> o
-            .: "number"
-          <*> o
-            .: "build_hash"
-          <*> o
-            .: "build_date"
-          <*> o
-            .: "build_snapshot"
-          <*> o
-            .: "lucene_version"
-
-versionNumberLens :: Lens' Version VersionNumber
-versionNumberLens = lens number (\x y -> x {number = y})
-
-versionBuildHashLens :: Lens' Version BuildHash
-versionBuildHashLens = lens build_hash (\x y -> x {build_hash = y})
-
-versionBuildDateLens :: Lens' Version UTCTime
-versionBuildDateLens = lens build_date (\x y -> x {build_date = y})
-
-versionBuildSnapshotLens :: Lens' Version Bool
-versionBuildSnapshotLens = lens build_snapshot (\x y -> x {build_snapshot = y})
-
-versionLuceneVersionLens :: Lens' Version VersionNumber
-versionLuceneVersionLens = lens lucene_version (\x y -> x {lucene_version = y})
-
--- | Traditional software versioning number
-newtype VersionNumber = VersionNumber
-  {versionNumber :: Versions.Version}
-  deriving stock (Eq, Ord, Show)
-
-instance ToJSON VersionNumber where
-  toJSON = toJSON . Versions.prettyVer . versionNumber
-
-instance FromJSON VersionNumber where
-  parseJSON = withText "VersionNumber" parse
-    where
-      parse t =
-        case Versions.version t of
-          (Left err) -> fail $ show err
-          (Right v) -> return (VersionNumber v)
+    DeletedDocuments (..),
+    DeletedDocumentsRetries (..),
+    EsAddress (..),
+    EsPassword (..),
+    EsUsername (..),
+    FullNodeId (..),
+    HealthStatus (..),
+    IndexedDocument (..),
+    InitialShardCount (..),
+    JVMBufferPoolStats (..),
+    JVMGCCollector (..),
+    JVMGCStats (..),
+    JVMMemoryInfo (..),
+    JVMMemoryPool (..),
+    JVMPoolStats (..),
+    JVMVersion (..),
+    LoadAvgs (..),
+    MacAddress (..),
+    NetworkInterfaceName (..),
+    NodeAttrFilter (..),
+    NodeAttrName (..),
+    NodeBreakerStats (..),
+    NodeBreakersStats (..),
+    NodeDataPathStats (..),
+    NodeFSStats (..),
+    NodeFSTotalStats (..),
+    NodeHTTPInfo (..),
+    NodeHTTPStats (..),
+    NodeIndicesStats (..),
+    NodeInfo (..),
+    NodeJVMInfo (..),
+    NodeJVMStats (..),
+    NodeName (..),
+    NodeNetworkInfo (..),
+    NodeNetworkInterface (..),
+    NodeNetworkStats (..),
+    NodeOSInfo (..),
+    NodeOSStats (..),
+    NodePluginInfo (..),
+    NodeProcessInfo (..),
+    NodeProcessStats (..),
+    NodeSelection (..),
+    NodeSelector (..),
+    NodeStats (..),
+    NodeThreadPoolInfo (..),
+    NodeThreadPoolStats (..),
+    NodeTransportInfo (..),
+    NodeTransportStats (..),
+    NodesInfo (..),
+    NodesStats (..),
+    PID (..),
+    PluginName (..),
+    ShardResult (..),
+    ShardsResult (..),
+    ThreadPool (..),
+    ThreadPoolSize (..),
+    ThreadPoolType (..),
+    Version (..),
+    VersionNumber (..),
+
+    -- * Optics
+    nodeAttrFilterNameLens,
+    nodeAttrFilterValuesLens,
+    nodeSelectionNodeListPrism,
+    nodeSelectorNodeByNamePrism,
+    nodeSelectorNodeByFullNodeIdPrism,
+    nodeSelectorNodeByHostPrism,
+    nodeSelectorNodeByAttributePrism,
+    nodesInfoListLens,
+    nodesClusterNameLens,
+    nodesStatsListLens,
+    nodesStatsClusterNameLens,
+    nodeStatsNameLens,
+    nodeStatsFullIdLens,
+    nodeStatsBreakersStatsLens,
+    nodeStatsHTTPLens,
+    nodeStatsTransportLens,
+    nodeStatsFSLens,
+    nodeStatsNetworkLens,
+    nodeStatsThreadPoolLens,
+    nodeStatsJVMLens,
+    nodeStatsProcessLens,
+    nodeStatsOSLens,
+    nodeStatsIndicesLens,
+    nodeStatsParentBreakerLens,
+    nodeStatsRequestBreakerLens,
+    nodeStatsFieldDataBreakerLens,
+    nodeBreakersStatsTrippedLens,
+    nodeBreakersStatsOverheadLens,
+    nodeBreakersStatsEstSizeLens,
+    nodeBreakersStatsLimitSizeLens,
+    nodeHTTPTotalStatsOpenedLens,
+    nodeHTTPStatsCurrentOpenLens,
+    nodeTransportStatsTXSizeLens,
+    nodeTransportStatsCountLens,
+    nodeTransportStatsRXSizeLens,
+    nodeTransportStatsRXCountLens,
+    nodeTransportStatsServerOpenLens,
+    nodeFSStatsDataPathsLens,
+    nodeFSStatsTotalLens,
+    nodeFSStatsTimestampLens,
+    nodeDataPathStatsDiskServiceTimeLens,
+    nodeDataPathStatsDiskQueueLens,
+    nodeDataPathStatsIOSizeLens,
+    nodeDataPathStatsWriteSizeLens,
+    nodeDataPathStatsReadSizeLens,
+    nodeDataPathStatsIOOpsLens,
+    nodeDataPathStatsWritesLens,
+    nodeDataPathStatsReadsLens,
+    nodeDataPathStatsAvailableLens,
+    nodeDataPathStatsFreeLens,
+    nodeDataPathStatsTotalLens,
+    nodeDataPathStatsTypeLens,
+    nodeDataPathStatsDeviceLens,
+    nodeDataPathStatsMountLens,
+    nodeDataPathStatsPathLens,
+    nodeFSTotalStatsDiskServiceTimeLens,
+    nodeFSTotalStatsDiskQueueLens,
+    nodeFSTotalStatsIOSizeLens,
+    nodeFSTotalStatsWriteSizeLens,
+    nodeFSTotalStatsReadSizeLens,
+    nodeFSTotalStatsIOOpsLens,
+    nodeFSTotalStatsWritesLens,
+    nodeFSTotalStatsReadsLens,
+    nodeFSTotalStatsAvailableLens,
+    nodeFSTotalStatsFreeLens,
+    nodeFSTotalStatsTotalLens,
+    nodeNetworkStatsTCPOutRSTsLens,
+    nodeNetworkStatsTCPInErrsLens,
+    nodeNetworkStatsTCPAttemptFailsLens,
+    nodeNetworkStatsTCPEstabResetsLens,
+    nodeNetworkStatsTCPRetransSegsLens,
+    nodeNetworkStatsTCPOutSegsLens,
+    nodeNetworkStatsTCPInSegsLens,
+    nodeNetworkStatsTCPCurrEstabLens,
+    nodeNetworkStatsTCPPassiveOpensLens,
+    nodeNetworkStatsTCPActiveOpensLens,
+    nodeThreadPoolStatsCompletedLens,
+    nodeThreadPoolStatsLargestLens,
+    nodeThreadPoolStatsRejectedLens,
+    nodeThreadPoolStatsActiveLens,
+    nodeThreadPoolStatsQueueLens,
+    nodeThreadPoolStatsThreadsLens,
+    nodeJVMStatsMappedBufferPoolLens,
+    nodeJVMStatsDirectBufferPoolLens,
+    nodeJVMStatsGCOldCollectorLens,
+    nodeJVMStatsGCYoungCollectorLens,
+    nodeJVMStatsPeakThreadsCountLens,
+    nodeJVMStatsThreadsCountLens,
+    nodeJVMStatsOldPoolLens,
+    nodeJVMStatsSurvivorPoolLens,
+    nodeJVMStatsYoungPoolLens,
+    nodeJVMStatsNonHeapCommittedLens,
+    nodeJVMStatsNonHeapUsedLens,
+    nodeJVMStatsHeapMaxLens,
+    nodeJVMStatsHeapCommittedLens,
+    nodeJVMStatsHeapUsedPercentLens,
+    nodeJVMStatsHeapUsedLens,
+    nodeJVMStatsUptimeLens,
+    nodeJVMStatsTimestampLens,
+    jvmBufferPoolStatsTotalCapacityLens,
+    jvmBufferPoolStatsUsedLens,
+    jvmBufferPoolStatsCountLens,
+    jvmGCStatsCollectionTimeLens,
+    jvmGCStatsCollectionCountLens,
+    jvmPoolStatsPeakMaxLens,
+    jvmPoolStatsPeakUsedLens,
+    jvmPoolStatsMaxLens,
+    jvmPoolStatsUsedLens,
+    nodeProcessStatsTimestampLens,
+    nodeProcessStatsOpenFDsLens,
+    nodeProcessStatsMaxFDsLens,
+    nodeProcessStatsCPUPercentLens,
+    nodeProcessStatsCPUTotalLens,
+    nodeProcessStatsMemTotalVirtualLens,
+    nodeOSStatsTimestampLens,
+    nodeOSStatsCPUPercentLens,
+    nodeOSStatsLoadLens,
+    nodeOSStatsMemTotalLens,
+    nodeOSStatsMemFreeLens,
+    nodeOSStatsMemFreePercentLens,
+    nodeOSStatsMemUsedLens,
+    nodeOSStatsMemUsedPercentLens,
+    nodeOSStatsSwapTotalLens,
+    nodeOSStatsSwapFreeLens,
+    nodeOSStatsSwapUsedLens,
+    loadAvgs1MinLens,
+    loadAvgs5MinLens,
+    loadAvgs15MinLens,
+    nodeIndicesStatsRecoveryThrottleTimeLens,
+    nodeIndicesStatsRecoveryCurrentAsTargetLens,
+    nodeIndicesStatsRecoveryCurrentAsSourceLens,
+    nodeIndicesStatsQueryCacheMissesLens,
+    nodeIndicesStatsQueryCacheHitsLens,
+    nodeIndicesStatsQueryCacheEvictionsLens,
+    nodeIndicesStatsQueryCacheSizeLens,
+    nodeIndicesStatsSuggestCurrentLens,
+    nodeIndicesStatsSuggestTimeLens,
+    nodeIndicesStatsSuggestTotalLens,
+    nodeIndicesStatsTranslogSizeLens,
+    nodeIndicesStatsTranslogOpsLens,
+    nodeIndicesStatsSegFixedBitSetMemoryLens,
+    nodeIndicesStatsSegVersionMapMemoryLens,
+    nodeIndicesStatsSegIndexWriterMaxMemoryLens,
+    nodeIndicesStatsSegIndexWriterMemoryLens,
+    nodeIndicesStatsSegMemoryLens,
+    nodeIndicesStatsSegCountLens,
+    nodeIndicesStatsCompletionSizeLens,
+    nodeIndicesStatsPercolateQueriesLens,
+    nodeIndicesStatsPercolateMemoryLens,
+    nodeIndicesStatsPercolateCurrentLens,
+    nodeIndicesStatsPercolateTimeLens,
+    nodeIndicesStatsPercolateTotalLens,
+    nodeIndicesStatsFieldDataEvictionsLens,
+    nodeIndicesStatsFieldDataMemoryLens,
+    nodeIndicesStatsWarmerTotalTimeLens,
+    nodeIndicesStatsWarmerTotalLens,
+    nodeIndicesStatsWarmerCurrentLens,
+    nodeIndicesStatsFlushTotalTimeLens,
+    nodeIndicesStatsFlushTotalLens,
+    nodeIndicesStatsRefreshTotalTimeLens,
+    nodeIndicesStatsRefreshTotalLens,
+    nodeIndicesStatsMergesTotalSizeLens,
+    nodeIndicesStatsMergesTotalDocsLens,
+    nodeIndicesStatsMergesTotalTimeLens,
+    nodeIndicesStatsMergesTotalLens,
+    nodeIndicesStatsMergesCurrentSizeLens,
+    nodeIndicesStatsMergesCurrentDocsLens,
+    nodeIndicesStatsMergesCurrentLens,
+    nodeIndicesStatsSearchFetchCurrentLens,
+    nodeIndicesStatsSearchFetchTimeLens,
+    nodeIndicesStatsSearchFetchTotalLens,
+    nodeIndicesStatsSearchQueryCurrentLens,
+    nodeIndicesStatsSearchQueryTimeLens,
+    nodeIndicesStatsSearchQueryTotalLens,
+    nodeIndicesStatsSearchOpenContextsLens,
+    nodeIndicesStatsGetCurrentLens,
+    nodeIndicesStatsGetMissingTimeLens,
+    nodeIndicesStatsGetMissingTotalLens,
+    nodeIndicesStatsGetExistsTimeLens,
+    nodeIndicesStatsGetExistsTotalLens,
+    nodeIndicesStatsGetTimeLens,
+    nodeIndicesStatsGetTotalLens,
+    nodeIndicesStatsIndexingThrottleTimeLens,
+    nodeIndicesStatsIndexingIsThrottledLens,
+    nodeIndicesStatsIndexingNoopUpdateTotalLens,
+    nodeIndicesStatsIndexingDeleteCurrentLens,
+    nodeIndicesStatsIndexingDeleteTimeLens,
+    nodeIndicesStatsIndexingDeleteTotalLens,
+    nodeIndicesStatsIndexingIndexCurrentLens,
+    nodeIndicesStatsIndexingIndexTimeLens,
+    nodeIndicesStatsIndexingTotalLens,
+    nodeIndicesStatsStoreThrottleTimeLens,
+    nodeIndicesStatsStoreSizeLens,
+    nodeIndicesStatsDocsDeletedLens,
+    nodeIndicesStatsDocsCountLens,
+    nodeInfoHTTPAddressLens,
+    nodeInfoBuildLens,
+    nodeInfoESVersionLens,
+    nodeInfoIPLens,
+    nodeInfoHostLens,
+    nodeInfoTransportAddressLens,
+    nodeInfoNameLens,
+    nodeInfoFullIdLens,
+    nodeInfoPluginsLens,
+    nodeInfoHTTPLens,
+    nodeInfoTransportLens,
+    nodeInfoNetworkLens,
+    nodeInfoThreadPoolLens,
+    nodeInfoJVMLens,
+    nodeInfoProcessLens,
+    nodeInfoOSLens,
+    nodeInfoSettingsLens,
+    nodePluginSiteLens,
+    nodePluginInfoJVMLens,
+    nodePluginInfoDescriptionLens,
+    nodePluginInfoVersionLens,
+    nodePluginInfoNameLens,
+    nodeHTTPInfoMaxContentLengthLens,
+    nodeHTTPInfopublishAddressLens,
+    nodeHTTPInfoBoundAddressesLens,
+    nodeTransportInfoProfilesLens,
+    nodeTransportInfoPublishAddressLens,
+    nodeTransportInfoBoundAddressLens,
+    boundTransportAddressPublishAddressLens,
+    boundTransportAddressBoundAddressesLens,
+    nodeNetworkInfoPrimaryInterfaceLens,
+    nodeNetworkInfoRefreshIntervalLens,
+    nodeNetworkInterfaceMacAddressLens,
+    nodeNetworkInterfaceNameLens,
+    nodeNetworkInterfaceAddressLens,
+    threadPoolNodeThreadPoolNameLens,
+    threadPoolNodeThreadPoolInfoLens,
+    nodeThreadPoolInfoQueueSizeLens,
+    nodeThreadPoolInfoKeepaliveLens,
+    nodeThreadPoolInfoMinLens,
+    nodeThreadPoolInfoMaxLens,
+    nodeThreadPoolInfoTypeLens,
+    threadPoolSizeBoundedPrism,
+    nodeJVMInfoMemoryPoolsLens,
+    nodeJVMInfoMemoryPoolsGCCollectorsLens,
+    nodeJVMInfoMemoryInfoLens,
+    nodeJVMInfoStartTimeLens,
+    nodeJVMInfoVMVendorLens,
+    nodeJVMInfoVMVersionLens,
+    nodeJVMInfoVMNameLens,
+    nodeJVMInfoVersionLens,
+    nodeJVMInfoPIDLens,
+    jvmMemoryInfoDirectMaxLens,
+    jvmMemoryInfoNonHeapMaxLens,
+    jvmMemoryInfoNonHeapInitLens,
+    jvmMemoryInfoHeapMaxLens,
+    jvmMemoryInfoHeapInitLens,
+    nodeOSInfoRefreshIntervalLens,
+    nodeOSInfoNameLens,
+    nodeOSInfoArchLens,
+    nodeOSInfoVersionLens,
+    nodeOSInfoAvailableProcessorsLens,
+    nodeOSInfoAllocatedProcessorsLens,
+    cpuInfoCacheSizeLens,
+    cpuInfoCoresPerSocketLens,
+    cpuInfoTotalSocketsLens,
+    cpuInfoTotalCoresLens,
+    cpuInfoMHZLens,
+    cpuInfoModelLens,
+    cpuInfoVendorLens,
+    nodeProcessInfoMLockAllLens,
+    nodeProcessInfoMaxFileDescriptorsLens,
+    nodeProcessInfoIdLens,
+    nodeProcessInfoRefreshIntervalLens,
+    initialShardCountExplicitShardsPrism,
+    shardsResultShardsLens,
+    shardResultTotalLens,
+    shardsResultSuccessfulLens,
+    shardsResultResultSkippedLens,
+    shardsResultFailedLens,
+    versionNumberLens,
+    versionBuildHashLens,
+    versionBuildDateLens,
+    versionBuildSnapshotLens,
+    versionLuceneVersionLens,
+    healthStatusClusterNameLens,
+    healthStatusStatusLens,
+    healthStatusTimedOutLens,
+    healthStatusNumberOfNodesLens,
+    healthStatusNumberOfDataNodesLens,
+    healthStatusActivePrimaryShardsLens,
+    healthStatusActiveShardsLens,
+    healthStatusRelocatingShardsLens,
+    healthStatusInitializingShardsLens,
+    healthStatusUnassignedShardsLens,
+    healthStatusDelayedUnassignedShardsLens,
+    healthStatusNumberOfPendingTasksLens,
+    healthStatusNumberOfInFlightFetchLens,
+    healthStatusTaskMaxWaitingInQueueMillisLens,
+    healthStatusActiveShardsPercentAsNumberLens,
+    indexedDocumentIndexLens,
+    indexedDocumentTypeLens,
+    indexedDocumentIdLens,
+    indexedDocumentVersionLens,
+    indexedDocumentResultLens,
+    indexedDocumentShardsLens,
+    indexedDocumentSeqNoLens,
+    indexedDocumentPrimaryTermLens,
+    deletedDocumentsTookLens,
+    deletedDocumentsTimedOutLens,
+    deletedDocumentsTotalLens,
+    deletedDocumentsDeletedLens,
+    deletedDocumentsBatchesLens,
+    deletedDocumentsVersionConflictsLens,
+    deletedDocumentsNoopsLens,
+    deletedDocumentsRetriesLens,
+    deletedDocumentsThrottledMillisLens,
+    deletedDocumentsRequestsPerSecondLens,
+    deletedDocumentsThrottledUntilMillisLens,
+    deletedDocumentsFailuresLens,
+    deletedDocumentsRetriesBulkLens,
+    deletedDocumentsRetriesSearchLens,
+  )
+where
+
+import qualified Data.Aeson.KeyMap as X
+import qualified Data.HashMap.Strict as HM
+import Data.Map.Strict (Map)
+import qualified Data.Text as T
+import qualified Data.Vector as V
+import qualified Data.Versions as Versions
+import Database.Bloodhound.Internal.Client.BHRequest
+import Database.Bloodhound.Internal.Utils.Imports
+import Database.Bloodhound.Internal.Utils.StringlyTyped
+import Database.Bloodhound.Internal.Versions.Common.Types.Newtypes
+import Database.Bloodhound.Internal.Versions.Common.Types.Units
+import GHC.Generics
+
+data NodeAttrFilter = NodeAttrFilter
+  { nodeAttrFilterName :: NodeAttrName,
+    nodeAttrFilterValues :: NonEmpty Text
+  }
+  deriving stock (Eq, Ord, Show)
+
+nodeAttrFilterNameLens :: Lens' NodeAttrFilter NodeAttrName
+nodeAttrFilterNameLens = lens nodeAttrFilterName (\x y -> x {nodeAttrFilterName = y})
+
+nodeAttrFilterValuesLens :: Lens' NodeAttrFilter (NonEmpty Text)
+nodeAttrFilterValuesLens = lens nodeAttrFilterValues (\x y -> x {nodeAttrFilterValues = y})
+
+newtype NodeAttrName = NodeAttrName Text deriving stock (Eq, Ord, Show)
+
+-- | 'NodeSelection' is used for most cluster APIs. See <https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster.html#cluster-nodes here> for more details.
+data NodeSelection
+  = -- | Whatever node receives this request
+    LocalNode
+  | NodeList (NonEmpty NodeSelector)
+  | AllNodes
+  deriving stock (Eq, Show)
+
+nodeSelectionNodeListPrism :: Prism' NodeSelection (NonEmpty NodeSelector)
+nodeSelectionNodeListPrism = prism NodeList extract
+  where
+    extract s =
+      case s of
+        NodeList x -> Right x
+        _ -> Left s
+
+-- | An exact match or pattern to identify a node. Note that All of
+-- these options support wildcarding, so your node name, server, attr
+-- name can all contain * characters to be a fuzzy match.
+data NodeSelector
+  = NodeByName NodeName
+  | NodeByFullNodeId FullNodeId
+  | -- | e.g. 10.0.0.1 or even 10.0.0.*
+    NodeByHost Server
+  | -- | NodeAttrName can be a pattern, e.g. rack*. The value can too.
+    NodeByAttribute NodeAttrName Text
+  deriving stock (Eq, Show)
+
+nodeSelectorNodeByNamePrism :: Prism' NodeSelector NodeName
+nodeSelectorNodeByNamePrism = prism NodeByName extract
+  where
+    extract s =
+      case s of
+        NodeByName x -> Right x
+        _ -> Left s
+
+nodeSelectorNodeByFullNodeIdPrism :: Prism' NodeSelector FullNodeId
+nodeSelectorNodeByFullNodeIdPrism = prism NodeByFullNodeId extract
+  where
+    extract s =
+      case s of
+        NodeByFullNodeId x -> Right x
+        _ -> Left s
+
+nodeSelectorNodeByHostPrism :: Prism' NodeSelector Server
+nodeSelectorNodeByHostPrism = prism NodeByHost extract
+  where
+    extract s =
+      case s of
+        NodeByHost x -> Right x
+        _ -> Left s
+
+nodeSelectorNodeByAttributePrism :: Prism' NodeSelector (NodeAttrName, Text)
+nodeSelectorNodeByAttributePrism = prism (uncurry NodeByAttribute) extract
+  where
+    extract s =
+      case s of
+        NodeByAttribute x y -> Right (x, y)
+        _ -> Left s
+
+-- | Unique, automatically-generated name assigned to nodes that are
+-- usually returned in node-oriented APIs.
+newtype FullNodeId = FullNodeId {fullNodeId :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+-- | A human-readable node name that is supplied by the user in the
+-- node config or automatically generated by Elasticsearch.
+newtype NodeName = NodeName {nodeName :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+newtype ClusterName = ClusterName {clusterName :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+-- | Username type used for HTTP Basic authentication. See 'basicAuthHook'.
+newtype EsUsername = EsUsername {esUsername :: Text} deriving (Read, Eq, Show)
+
+-- | Password type used for HTTP Basic authentication. See 'basicAuthHook'.
+newtype EsPassword = EsPassword {esPassword :: Text} deriving (Read, Eq, Show)
+
+data NodesInfo = NodesInfo
+  { nodesInfo :: [NodeInfo],
+    nodesClusterName :: ClusterName
+  }
+  deriving stock (Eq, Show)
+
+nodesInfoListLens :: Lens' NodesInfo [NodeInfo]
+nodesInfoListLens = lens nodesInfo (\x y -> x {nodesInfo = y})
+
+nodesClusterNameLens :: Lens' NodesInfo ClusterName
+nodesClusterNameLens = lens nodesClusterName (\x y -> x {nodesClusterName = y})
+
+data NodesStats = NodesStats
+  { nodesStats :: [NodeStats],
+    nodesStatsClusterName :: ClusterName
+  }
+  deriving stock (Eq, Show)
+
+nodesStatsListLens :: Lens' NodesStats [NodeStats]
+nodesStatsListLens = lens nodesStats (\x y -> x {nodesStats = y})
+
+nodesStatsClusterNameLens :: Lens' NodesStats ClusterName
+nodesStatsClusterNameLens = lens nodesStatsClusterName (\x y -> x {nodesStatsClusterName = y})
+
+data NodeStats = NodeStats
+  { nodeStatsName :: NodeName,
+    nodeStatsFullId :: FullNodeId,
+    nodeStatsBreakersStats :: Maybe NodeBreakersStats,
+    nodeStatsHTTP :: NodeHTTPStats,
+    nodeStatsTransport :: NodeTransportStats,
+    nodeStatsFS :: NodeFSStats,
+    nodeStatsNetwork :: Maybe NodeNetworkStats,
+    nodeStatsThreadPool :: Map Text NodeThreadPoolStats,
+    nodeStatsJVM :: NodeJVMStats,
+    nodeStatsProcess :: NodeProcessStats,
+    nodeStatsOS :: NodeOSStats,
+    nodeStatsIndices :: NodeIndicesStats
+  }
+  deriving stock (Eq, Show)
+
+nodeStatsNameLens :: Lens' NodeStats NodeName
+nodeStatsNameLens = lens nodeStatsName (\x y -> x {nodeStatsName = y})
+
+nodeStatsFullIdLens :: Lens' NodeStats FullNodeId
+nodeStatsFullIdLens = lens nodeStatsFullId (\x y -> x {nodeStatsFullId = y})
+
+nodeStatsBreakersStatsLens :: Lens' NodeStats (Maybe NodeBreakersStats)
+nodeStatsBreakersStatsLens = lens nodeStatsBreakersStats (\x y -> x {nodeStatsBreakersStats = y})
+
+nodeStatsHTTPLens :: Lens' NodeStats NodeHTTPStats
+nodeStatsHTTPLens = lens nodeStatsHTTP (\x y -> x {nodeStatsHTTP = y})
+
+nodeStatsTransportLens :: Lens' NodeStats NodeTransportStats
+nodeStatsTransportLens = lens nodeStatsTransport (\x y -> x {nodeStatsTransport = y})
+
+nodeStatsFSLens :: Lens' NodeStats NodeFSStats
+nodeStatsFSLens = lens nodeStatsFS (\x y -> x {nodeStatsFS = y})
+
+nodeStatsNetworkLens :: Lens' NodeStats (Maybe NodeNetworkStats)
+nodeStatsNetworkLens = lens nodeStatsNetwork (\x y -> x {nodeStatsNetwork = y})
+
+nodeStatsThreadPoolLens :: Lens' NodeStats (Map Text NodeThreadPoolStats)
+nodeStatsThreadPoolLens = lens nodeStatsThreadPool (\x y -> x {nodeStatsThreadPool = y})
+
+nodeStatsJVMLens :: Lens' NodeStats NodeJVMStats
+nodeStatsJVMLens = lens nodeStatsJVM (\x y -> x {nodeStatsJVM = y})
+
+nodeStatsProcessLens :: Lens' NodeStats NodeProcessStats
+nodeStatsProcessLens = lens nodeStatsProcess (\x y -> x {nodeStatsProcess = y})
+
+nodeStatsOSLens :: Lens' NodeStats NodeOSStats
+nodeStatsOSLens = lens nodeStatsOS (\x y -> x {nodeStatsOS = y})
+
+nodeStatsIndicesLens :: Lens' NodeStats NodeIndicesStats
+nodeStatsIndicesLens = lens nodeStatsIndices (\x y -> x {nodeStatsIndices = y})
+
+data NodeBreakersStats = NodeBreakersStats
+  { nodeStatsParentBreaker :: NodeBreakerStats,
+    nodeStatsRequestBreaker :: NodeBreakerStats,
+    nodeStatsFieldDataBreaker :: NodeBreakerStats
+  }
+  deriving stock (Eq, Show)
+
+nodeStatsParentBreakerLens :: Lens' NodeBreakersStats NodeBreakerStats
+nodeStatsParentBreakerLens = lens nodeStatsParentBreaker (\x y -> x {nodeStatsParentBreaker = y})
+
+nodeStatsRequestBreakerLens :: Lens' NodeBreakersStats NodeBreakerStats
+nodeStatsRequestBreakerLens = lens nodeStatsRequestBreaker (\x y -> x {nodeStatsRequestBreaker = y})
+
+nodeStatsFieldDataBreakerLens :: Lens' NodeBreakersStats NodeBreakerStats
+nodeStatsFieldDataBreakerLens = lens nodeStatsFieldDataBreaker (\x y -> x {nodeStatsFieldDataBreaker = y})
+
+data NodeBreakerStats = NodeBreakerStats
+  { nodeBreakersTripped :: Int,
+    nodeBreakersOverhead :: Double,
+    nodeBreakersEstSize :: Bytes,
+    nodeBreakersLimitSize :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+nodeBreakersStatsTrippedLens :: Lens' NodeBreakerStats Int
+nodeBreakersStatsTrippedLens = lens nodeBreakersTripped (\x y -> x {nodeBreakersTripped = y})
+
+nodeBreakersStatsOverheadLens :: Lens' NodeBreakerStats Double
+nodeBreakersStatsOverheadLens = lens nodeBreakersOverhead (\x y -> x {nodeBreakersOverhead = y})
+
+nodeBreakersStatsEstSizeLens :: Lens' NodeBreakerStats Bytes
+nodeBreakersStatsEstSizeLens = lens nodeBreakersEstSize (\x y -> x {nodeBreakersEstSize = y})
+
+nodeBreakersStatsLimitSizeLens :: Lens' NodeBreakerStats Bytes
+nodeBreakersStatsLimitSizeLens = lens nodeBreakersLimitSize (\x y -> x {nodeBreakersLimitSize = y})
+
+data NodeHTTPStats = NodeHTTPStats
+  { nodeHTTPTotalOpened :: Int,
+    nodeHTTPCurrentOpen :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeHTTPTotalStatsOpenedLens :: Lens' NodeHTTPStats Int
+nodeHTTPTotalStatsOpenedLens = lens nodeHTTPTotalOpened (\x y -> x {nodeHTTPTotalOpened = y})
+
+nodeHTTPStatsCurrentOpenLens :: Lens' NodeHTTPStats Int
+nodeHTTPStatsCurrentOpenLens = lens nodeHTTPCurrentOpen (\x y -> x {nodeHTTPCurrentOpen = y})
+
+data NodeTransportStats = NodeTransportStats
+  { nodeTransportTXSize :: Bytes,
+    nodeTransportCount :: Int,
+    nodeTransportRXSize :: Bytes,
+    nodeTransportRXCount :: Int,
+    nodeTransportServerOpen :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeTransportStatsTXSizeLens :: Lens' NodeTransportStats Bytes
+nodeTransportStatsTXSizeLens = lens nodeTransportTXSize (\x y -> x {nodeTransportTXSize = y})
+
+nodeTransportStatsCountLens :: Lens' NodeTransportStats Int
+nodeTransportStatsCountLens = lens nodeTransportCount (\x y -> x {nodeTransportCount = y})
+
+nodeTransportStatsRXSizeLens :: Lens' NodeTransportStats Bytes
+nodeTransportStatsRXSizeLens = lens nodeTransportRXSize (\x y -> x {nodeTransportRXSize = y})
+
+nodeTransportStatsRXCountLens :: Lens' NodeTransportStats Int
+nodeTransportStatsRXCountLens = lens nodeTransportRXCount (\x y -> x {nodeTransportRXCount = y})
+
+nodeTransportStatsServerOpenLens :: Lens' NodeTransportStats Int
+nodeTransportStatsServerOpenLens = lens nodeTransportServerOpen (\x y -> x {nodeTransportServerOpen = y})
+
+data NodeFSStats = NodeFSStats
+  { nodeFSDataPaths :: [NodeDataPathStats],
+    nodeFSTotal :: NodeFSTotalStats,
+    nodeFSTimestamp :: UTCTime
+  }
+  deriving stock (Eq, Show)
+
+nodeFSStatsDataPathsLens :: Lens' NodeFSStats [NodeDataPathStats]
+nodeFSStatsDataPathsLens = lens nodeFSDataPaths (\x y -> x {nodeFSDataPaths = y})
+
+nodeFSStatsTotalLens :: Lens' NodeFSStats NodeFSTotalStats
+nodeFSStatsTotalLens = lens nodeFSTotal (\x y -> x {nodeFSTotal = y})
+
+nodeFSStatsTimestampLens :: Lens' NodeFSStats UTCTime
+nodeFSStatsTimestampLens = lens nodeFSTimestamp (\x y -> x {nodeFSTimestamp = y})
+
+data NodeDataPathStats = NodeDataPathStats
+  { nodeDataPathDiskServiceTime :: Maybe Double,
+    nodeDataPathDiskQueue :: Maybe Double,
+    nodeDataPathIOSize :: Maybe Bytes,
+    nodeDataPathWriteSize :: Maybe Bytes,
+    nodeDataPathReadSize :: Maybe Bytes,
+    nodeDataPathIOOps :: Maybe Int,
+    nodeDataPathWrites :: Maybe Int,
+    nodeDataPathReads :: Maybe Int,
+    nodeDataPathAvailable :: Bytes,
+    nodeDataPathFree :: Bytes,
+    nodeDataPathTotal :: Bytes,
+    nodeDataPathType :: Maybe Text,
+    nodeDataPathDevice :: Maybe Text,
+    nodeDataPathMount :: Text,
+    nodeDataPathPath :: Text
+  }
+  deriving stock (Eq, Show)
+
+nodeDataPathStatsDiskServiceTimeLens :: Lens' NodeDataPathStats (Maybe Double)
+nodeDataPathStatsDiskServiceTimeLens = lens nodeDataPathDiskServiceTime (\x y -> x {nodeDataPathDiskServiceTime = y})
+
+nodeDataPathStatsDiskQueueLens :: Lens' NodeDataPathStats (Maybe Double)
+nodeDataPathStatsDiskQueueLens = lens nodeDataPathDiskQueue (\x y -> x {nodeDataPathDiskQueue = y})
+
+nodeDataPathStatsIOSizeLens :: Lens' NodeDataPathStats (Maybe Bytes)
+nodeDataPathStatsIOSizeLens = lens nodeDataPathIOSize (\x y -> x {nodeDataPathIOSize = y})
+
+nodeDataPathStatsWriteSizeLens :: Lens' NodeDataPathStats (Maybe Bytes)
+nodeDataPathStatsWriteSizeLens = lens nodeDataPathWriteSize (\x y -> x {nodeDataPathWriteSize = y})
+
+nodeDataPathStatsReadSizeLens :: Lens' NodeDataPathStats (Maybe Bytes)
+nodeDataPathStatsReadSizeLens = lens nodeDataPathReadSize (\x y -> x {nodeDataPathReadSize = y})
+
+nodeDataPathStatsIOOpsLens :: Lens' NodeDataPathStats (Maybe Int)
+nodeDataPathStatsIOOpsLens = lens nodeDataPathIOOps (\x y -> x {nodeDataPathIOOps = y})
+
+nodeDataPathStatsWritesLens :: Lens' NodeDataPathStats (Maybe Int)
+nodeDataPathStatsWritesLens = lens nodeDataPathWrites (\x y -> x {nodeDataPathWrites = y})
+
+nodeDataPathStatsReadsLens :: Lens' NodeDataPathStats (Maybe Int)
+nodeDataPathStatsReadsLens = lens nodeDataPathReads (\x y -> x {nodeDataPathReads = y})
+
+nodeDataPathStatsAvailableLens :: Lens' NodeDataPathStats Bytes
+nodeDataPathStatsAvailableLens = lens nodeDataPathAvailable (\x y -> x {nodeDataPathAvailable = y})
+
+nodeDataPathStatsFreeLens :: Lens' NodeDataPathStats Bytes
+nodeDataPathStatsFreeLens = lens nodeDataPathFree (\x y -> x {nodeDataPathFree = y})
+
+nodeDataPathStatsTotalLens :: Lens' NodeDataPathStats Bytes
+nodeDataPathStatsTotalLens = lens nodeDataPathTotal (\x y -> x {nodeDataPathTotal = y})
+
+nodeDataPathStatsTypeLens :: Lens' NodeDataPathStats (Maybe Text)
+nodeDataPathStatsTypeLens = lens nodeDataPathType (\x y -> x {nodeDataPathType = y})
+
+nodeDataPathStatsDeviceLens :: Lens' NodeDataPathStats (Maybe Text)
+nodeDataPathStatsDeviceLens = lens nodeDataPathDevice (\x y -> x {nodeDataPathDevice = y})
+
+nodeDataPathStatsMountLens :: Lens' NodeDataPathStats Text
+nodeDataPathStatsMountLens = lens nodeDataPathMount (\x y -> x {nodeDataPathMount = y})
+
+nodeDataPathStatsPathLens :: Lens' NodeDataPathStats Text
+nodeDataPathStatsPathLens = lens nodeDataPathPath (\x y -> x {nodeDataPathPath = y})
+
+data NodeFSTotalStats = NodeFSTotalStats
+  { nodeFSTotalDiskServiceTime :: Maybe Double,
+    nodeFSTotalDiskQueue :: Maybe Double,
+    nodeFSTotalIOSize :: Maybe Bytes,
+    nodeFSTotalWriteSize :: Maybe Bytes,
+    nodeFSTotalReadSize :: Maybe Bytes,
+    nodeFSTotalIOOps :: Maybe Int,
+    nodeFSTotalWrites :: Maybe Int,
+    nodeFSTotalReads :: Maybe Int,
+    nodeFSTotalAvailable :: Bytes,
+    nodeFSTotalFree :: Bytes,
+    nodeFSTotalTotal :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+nodeFSTotalStatsDiskServiceTimeLens :: Lens' NodeFSTotalStats (Maybe Double)
+nodeFSTotalStatsDiskServiceTimeLens = lens nodeFSTotalDiskServiceTime (\x y -> x {nodeFSTotalDiskServiceTime = y})
+
+nodeFSTotalStatsDiskQueueLens :: Lens' NodeFSTotalStats (Maybe Double)
+nodeFSTotalStatsDiskQueueLens = lens nodeFSTotalDiskQueue (\x y -> x {nodeFSTotalDiskQueue = y})
+
+nodeFSTotalStatsIOSizeLens :: Lens' NodeFSTotalStats (Maybe Bytes)
+nodeFSTotalStatsIOSizeLens = lens nodeFSTotalIOSize (\x y -> x {nodeFSTotalIOSize = y})
+
+nodeFSTotalStatsWriteSizeLens :: Lens' NodeFSTotalStats (Maybe Bytes)
+nodeFSTotalStatsWriteSizeLens = lens nodeFSTotalWriteSize (\x y -> x {nodeFSTotalWriteSize = y})
+
+nodeFSTotalStatsReadSizeLens :: Lens' NodeFSTotalStats (Maybe Bytes)
+nodeFSTotalStatsReadSizeLens = lens nodeFSTotalReadSize (\x y -> x {nodeFSTotalReadSize = y})
+
+nodeFSTotalStatsIOOpsLens :: Lens' NodeFSTotalStats (Maybe Int)
+nodeFSTotalStatsIOOpsLens = lens nodeFSTotalIOOps (\x y -> x {nodeFSTotalIOOps = y})
+
+nodeFSTotalStatsWritesLens :: Lens' NodeFSTotalStats (Maybe Int)
+nodeFSTotalStatsWritesLens = lens nodeFSTotalWrites (\x y -> x {nodeFSTotalWrites = y})
+
+nodeFSTotalStatsReadsLens :: Lens' NodeFSTotalStats (Maybe Int)
+nodeFSTotalStatsReadsLens = lens nodeFSTotalReads (\x y -> x {nodeFSTotalReads = y})
+
+nodeFSTotalStatsAvailableLens :: Lens' NodeFSTotalStats Bytes
+nodeFSTotalStatsAvailableLens = lens nodeFSTotalAvailable (\x y -> x {nodeFSTotalAvailable = y})
+
+nodeFSTotalStatsFreeLens :: Lens' NodeFSTotalStats Bytes
+nodeFSTotalStatsFreeLens = lens nodeFSTotalFree (\x y -> x {nodeFSTotalFree = y})
+
+nodeFSTotalStatsTotalLens :: Lens' NodeFSTotalStats Bytes
+nodeFSTotalStatsTotalLens = lens nodeFSTotalTotal (\x y -> x {nodeFSTotalTotal = y})
+
+data NodeNetworkStats = NodeNetworkStats
+  { nodeNetTCPOutRSTs :: Int,
+    nodeNetTCPInErrs :: Int,
+    nodeNetTCPAttemptFails :: Int,
+    nodeNetTCPEstabResets :: Int,
+    nodeNetTCPRetransSegs :: Int,
+    nodeNetTCPOutSegs :: Int,
+    nodeNetTCPInSegs :: Int,
+    nodeNetTCPCurrEstab :: Int,
+    nodeNetTCPPassiveOpens :: Int,
+    nodeNetTCPActiveOpens :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeNetworkStatsTCPOutRSTsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPOutRSTsLens = lens nodeNetTCPOutRSTs (\x y -> x {nodeNetTCPOutRSTs = y})
+
+nodeNetworkStatsTCPInErrsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPInErrsLens = lens nodeNetTCPInErrs (\x y -> x {nodeNetTCPInErrs = y})
+
+nodeNetworkStatsTCPAttemptFailsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPAttemptFailsLens = lens nodeNetTCPAttemptFails (\x y -> x {nodeNetTCPAttemptFails = y})
+
+nodeNetworkStatsTCPEstabResetsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPEstabResetsLens = lens nodeNetTCPEstabResets (\x y -> x {nodeNetTCPEstabResets = y})
+
+nodeNetworkStatsTCPRetransSegsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPRetransSegsLens = lens nodeNetTCPRetransSegs (\x y -> x {nodeNetTCPRetransSegs = y})
+
+nodeNetworkStatsTCPOutSegsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPOutSegsLens = lens nodeNetTCPOutSegs (\x y -> x {nodeNetTCPOutSegs = y})
+
+nodeNetworkStatsTCPInSegsLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPInSegsLens = lens nodeNetTCPInSegs (\x y -> x {nodeNetTCPInSegs = y})
+
+nodeNetworkStatsTCPCurrEstabLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPCurrEstabLens = lens nodeNetTCPCurrEstab (\x y -> x {nodeNetTCPCurrEstab = y})
+
+nodeNetworkStatsTCPPassiveOpensLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPPassiveOpensLens = lens nodeNetTCPPassiveOpens (\x y -> x {nodeNetTCPPassiveOpens = y})
+
+nodeNetworkStatsTCPActiveOpensLens :: Lens' NodeNetworkStats Int
+nodeNetworkStatsTCPActiveOpensLens = lens nodeNetTCPActiveOpens (\x y -> x {nodeNetTCPActiveOpens = y})
+
+data NodeThreadPoolStats = NodeThreadPoolStats
+  { nodeThreadPoolCompleted :: Int,
+    nodeThreadPoolLargest :: Int,
+    nodeThreadPoolRejected :: Int,
+    nodeThreadPoolActive :: Int,
+    nodeThreadPoolQueue :: Int,
+    nodeThreadPoolThreads :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeThreadPoolStatsCompletedLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsCompletedLens = lens nodeThreadPoolCompleted (\x y -> x {nodeThreadPoolCompleted = y})
+
+nodeThreadPoolStatsLargestLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsLargestLens = lens nodeThreadPoolLargest (\x y -> x {nodeThreadPoolLargest = y})
+
+nodeThreadPoolStatsRejectedLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsRejectedLens = lens nodeThreadPoolRejected (\x y -> x {nodeThreadPoolRejected = y})
+
+nodeThreadPoolStatsActiveLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsActiveLens = lens nodeThreadPoolActive (\x y -> x {nodeThreadPoolActive = y})
+
+nodeThreadPoolStatsQueueLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsQueueLens = lens nodeThreadPoolQueue (\x y -> x {nodeThreadPoolQueue = y})
+
+nodeThreadPoolStatsThreadsLens :: Lens' NodeThreadPoolStats Int
+nodeThreadPoolStatsThreadsLens = lens nodeThreadPoolThreads (\x y -> x {nodeThreadPoolThreads = y})
+
+data NodeJVMStats = NodeJVMStats
+  { nodeJVMStatsMappedBufferPool :: JVMBufferPoolStats,
+    nodeJVMStatsDirectBufferPool :: JVMBufferPoolStats,
+    nodeJVMStatsGCOldCollector :: JVMGCStats,
+    nodeJVMStatsGCYoungCollector :: JVMGCStats,
+    nodeJVMStatsPeakThreadsCount :: Int,
+    nodeJVMStatsThreadsCount :: Int,
+    nodeJVMStatsOldPool :: JVMPoolStats,
+    nodeJVMStatsSurvivorPool :: JVMPoolStats,
+    nodeJVMStatsYoungPool :: JVMPoolStats,
+    nodeJVMStatsNonHeapCommitted :: Bytes,
+    nodeJVMStatsNonHeapUsed :: Bytes,
+    nodeJVMStatsHeapMax :: Bytes,
+    nodeJVMStatsHeapCommitted :: Bytes,
+    nodeJVMStatsHeapUsedPercent :: Int,
+    nodeJVMStatsHeapUsed :: Bytes,
+    nodeJVMStatsUptime :: NominalDiffTime,
+    nodeJVMStatsTimestamp :: UTCTime
+  }
+  deriving stock (Eq, Show)
+
+nodeJVMStatsMappedBufferPoolLens :: Lens' NodeJVMStats JVMBufferPoolStats
+nodeJVMStatsMappedBufferPoolLens = lens nodeJVMStatsMappedBufferPool (\x y -> x {nodeJVMStatsMappedBufferPool = y})
+
+nodeJVMStatsDirectBufferPoolLens :: Lens' NodeJVMStats JVMBufferPoolStats
+nodeJVMStatsDirectBufferPoolLens = lens nodeJVMStatsDirectBufferPool (\x y -> x {nodeJVMStatsDirectBufferPool = y})
+
+nodeJVMStatsGCOldCollectorLens :: Lens' NodeJVMStats JVMGCStats
+nodeJVMStatsGCOldCollectorLens = lens nodeJVMStatsGCOldCollector (\x y -> x {nodeJVMStatsGCOldCollector = y})
+
+nodeJVMStatsGCYoungCollectorLens :: Lens' NodeJVMStats JVMGCStats
+nodeJVMStatsGCYoungCollectorLens = lens nodeJVMStatsGCYoungCollector (\x y -> x {nodeJVMStatsGCYoungCollector = y})
+
+nodeJVMStatsPeakThreadsCountLens :: Lens' NodeJVMStats Int
+nodeJVMStatsPeakThreadsCountLens = lens nodeJVMStatsPeakThreadsCount (\x y -> x {nodeJVMStatsPeakThreadsCount = y})
+
+nodeJVMStatsThreadsCountLens :: Lens' NodeJVMStats Int
+nodeJVMStatsThreadsCountLens = lens nodeJVMStatsThreadsCount (\x y -> x {nodeJVMStatsThreadsCount = y})
+
+nodeJVMStatsOldPoolLens :: Lens' NodeJVMStats JVMPoolStats
+nodeJVMStatsOldPoolLens = lens nodeJVMStatsOldPool (\x y -> x {nodeJVMStatsOldPool = y})
+
+nodeJVMStatsSurvivorPoolLens :: Lens' NodeJVMStats JVMPoolStats
+nodeJVMStatsSurvivorPoolLens = lens nodeJVMStatsSurvivorPool (\x y -> x {nodeJVMStatsSurvivorPool = y})
+
+nodeJVMStatsYoungPoolLens :: Lens' NodeJVMStats JVMPoolStats
+nodeJVMStatsYoungPoolLens = lens nodeJVMStatsYoungPool (\x y -> x {nodeJVMStatsYoungPool = y})
+
+nodeJVMStatsNonHeapCommittedLens :: Lens' NodeJVMStats Bytes
+nodeJVMStatsNonHeapCommittedLens = lens nodeJVMStatsNonHeapCommitted (\x y -> x {nodeJVMStatsNonHeapCommitted = y})
+
+nodeJVMStatsNonHeapUsedLens :: Lens' NodeJVMStats Bytes
+nodeJVMStatsNonHeapUsedLens = lens nodeJVMStatsNonHeapUsed (\x y -> x {nodeJVMStatsNonHeapUsed = y})
+
+nodeJVMStatsHeapMaxLens :: Lens' NodeJVMStats Bytes
+nodeJVMStatsHeapMaxLens = lens nodeJVMStatsHeapMax (\x y -> x {nodeJVMStatsHeapMax = y})
+
+nodeJVMStatsHeapCommittedLens :: Lens' NodeJVMStats Bytes
+nodeJVMStatsHeapCommittedLens = lens nodeJVMStatsHeapCommitted (\x y -> x {nodeJVMStatsHeapCommitted = y})
+
+nodeJVMStatsHeapUsedPercentLens :: Lens' NodeJVMStats Int
+nodeJVMStatsHeapUsedPercentLens = lens nodeJVMStatsHeapUsedPercent (\x y -> x {nodeJVMStatsHeapUsedPercent = y})
+
+nodeJVMStatsHeapUsedLens :: Lens' NodeJVMStats Bytes
+nodeJVMStatsHeapUsedLens = lens nodeJVMStatsHeapUsed (\x y -> x {nodeJVMStatsHeapUsed = y})
+
+nodeJVMStatsUptimeLens :: Lens' NodeJVMStats NominalDiffTime
+nodeJVMStatsUptimeLens = lens nodeJVMStatsUptime (\x y -> x {nodeJVMStatsUptime = y})
+
+nodeJVMStatsTimestampLens :: Lens' NodeJVMStats UTCTime
+nodeJVMStatsTimestampLens = lens nodeJVMStatsTimestamp (\x y -> x {nodeJVMStatsTimestamp = y})
+
+data JVMBufferPoolStats = JVMBufferPoolStats
+  { jvmBufferPoolStatsTotalCapacity :: Bytes,
+    jvmBufferPoolStatsUsed :: Bytes,
+    jvmBufferPoolStatsCount :: Int
+  }
+  deriving stock (Eq, Show)
+
+jvmBufferPoolStatsTotalCapacityLens :: Lens' JVMBufferPoolStats Bytes
+jvmBufferPoolStatsTotalCapacityLens = lens jvmBufferPoolStatsTotalCapacity (\x y -> x {jvmBufferPoolStatsTotalCapacity = y})
+
+jvmBufferPoolStatsUsedLens :: Lens' JVMBufferPoolStats Bytes
+jvmBufferPoolStatsUsedLens = lens jvmBufferPoolStatsUsed (\x y -> x {jvmBufferPoolStatsUsed = y})
+
+jvmBufferPoolStatsCountLens :: Lens' JVMBufferPoolStats Int
+jvmBufferPoolStatsCountLens = lens jvmBufferPoolStatsCount (\x y -> x {jvmBufferPoolStatsCount = y})
+
+data JVMGCStats = JVMGCStats
+  { jvmGCStatsCollectionTime :: NominalDiffTime,
+    jvmGCStatsCollectionCount :: Int
+  }
+  deriving stock (Eq, Show)
+
+jvmGCStatsCollectionTimeLens :: Lens' JVMGCStats NominalDiffTime
+jvmGCStatsCollectionTimeLens = lens jvmGCStatsCollectionTime (\x y -> x {jvmGCStatsCollectionTime = y})
+
+jvmGCStatsCollectionCountLens :: Lens' JVMGCStats Int
+jvmGCStatsCollectionCountLens = lens jvmGCStatsCollectionCount (\x y -> x {jvmGCStatsCollectionCount = y})
+
+data JVMPoolStats = JVMPoolStats
+  { jvmPoolStatsPeakMax :: Bytes,
+    jvmPoolStatsPeakUsed :: Bytes,
+    jvmPoolStatsMax :: Bytes,
+    jvmPoolStatsUsed :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+jvmPoolStatsPeakMaxLens :: Lens' JVMPoolStats Bytes
+jvmPoolStatsPeakMaxLens = lens jvmPoolStatsPeakMax (\x y -> x {jvmPoolStatsPeakMax = y})
+
+jvmPoolStatsPeakUsedLens :: Lens' JVMPoolStats Bytes
+jvmPoolStatsPeakUsedLens = lens jvmPoolStatsPeakUsed (\x y -> x {jvmPoolStatsPeakUsed = y})
+
+jvmPoolStatsMaxLens :: Lens' JVMPoolStats Bytes
+jvmPoolStatsMaxLens = lens jvmPoolStatsMax (\x y -> x {jvmPoolStatsMax = y})
+
+jvmPoolStatsUsedLens :: Lens' JVMPoolStats Bytes
+jvmPoolStatsUsedLens = lens jvmPoolStatsUsed (\x y -> x {jvmPoolStatsUsed = y})
+
+data NodeProcessStats = NodeProcessStats
+  { nodeProcessTimestamp :: UTCTime,
+    nodeProcessOpenFDs :: Int,
+    nodeProcessMaxFDs :: Int,
+    nodeProcessCPUPercent :: Int,
+    nodeProcessCPUTotal :: NominalDiffTime,
+    nodeProcessMemTotalVirtual :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+nodeProcessStatsTimestampLens :: Lens' NodeProcessStats UTCTime
+nodeProcessStatsTimestampLens = lens nodeProcessTimestamp (\x y -> x {nodeProcessTimestamp = y})
+
+nodeProcessStatsOpenFDsLens :: Lens' NodeProcessStats Int
+nodeProcessStatsOpenFDsLens = lens nodeProcessOpenFDs (\x y -> x {nodeProcessOpenFDs = y})
+
+nodeProcessStatsMaxFDsLens :: Lens' NodeProcessStats Int
+nodeProcessStatsMaxFDsLens = lens nodeProcessMaxFDs (\x y -> x {nodeProcessMaxFDs = y})
+
+nodeProcessStatsCPUPercentLens :: Lens' NodeProcessStats Int
+nodeProcessStatsCPUPercentLens = lens nodeProcessCPUPercent (\x y -> x {nodeProcessCPUPercent = y})
+
+nodeProcessStatsCPUTotalLens :: Lens' NodeProcessStats NominalDiffTime
+nodeProcessStatsCPUTotalLens = lens nodeProcessCPUTotal (\x y -> x {nodeProcessCPUTotal = y})
+
+nodeProcessStatsMemTotalVirtualLens :: Lens' NodeProcessStats Bytes
+nodeProcessStatsMemTotalVirtualLens = lens nodeProcessMemTotalVirtual (\x y -> x {nodeProcessMemTotalVirtual = y})
+
+data NodeOSStats = NodeOSStats
+  { nodeOSTimestamp :: UTCTime,
+    nodeOSCPUPercent :: Int,
+    nodeOSLoad :: Maybe LoadAvgs,
+    nodeOSMemTotal :: Bytes,
+    nodeOSMemFree :: Bytes,
+    nodeOSMemFreePercent :: Int,
+    nodeOSMemUsed :: Bytes,
+    nodeOSMemUsedPercent :: Int,
+    nodeOSSwapTotal :: Bytes,
+    nodeOSSwapFree :: Bytes,
+    nodeOSSwapUsed :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+nodeOSStatsTimestampLens :: Lens' NodeOSStats UTCTime
+nodeOSStatsTimestampLens = lens nodeOSTimestamp (\x y -> x {nodeOSTimestamp = y})
+
+nodeOSStatsCPUPercentLens :: Lens' NodeOSStats Int
+nodeOSStatsCPUPercentLens = lens nodeOSCPUPercent (\x y -> x {nodeOSCPUPercent = y})
+
+nodeOSStatsLoadLens :: Lens' NodeOSStats (Maybe LoadAvgs)
+nodeOSStatsLoadLens = lens nodeOSLoad (\x y -> x {nodeOSLoad = y})
+
+nodeOSStatsMemTotalLens :: Lens' NodeOSStats Bytes
+nodeOSStatsMemTotalLens = lens nodeOSMemTotal (\x y -> x {nodeOSMemTotal = y})
+
+nodeOSStatsMemFreeLens :: Lens' NodeOSStats Bytes
+nodeOSStatsMemFreeLens = lens nodeOSMemFree (\x y -> x {nodeOSMemFree = y})
+
+nodeOSStatsMemFreePercentLens :: Lens' NodeOSStats Int
+nodeOSStatsMemFreePercentLens = lens nodeOSMemFreePercent (\x y -> x {nodeOSMemFreePercent = y})
+
+nodeOSStatsMemUsedLens :: Lens' NodeOSStats Bytes
+nodeOSStatsMemUsedLens = lens nodeOSMemUsed (\x y -> x {nodeOSMemUsed = y})
+
+nodeOSStatsMemUsedPercentLens :: Lens' NodeOSStats Int
+nodeOSStatsMemUsedPercentLens = lens nodeOSMemUsedPercent (\x y -> x {nodeOSMemUsedPercent = y})
+
+nodeOSStatsSwapTotalLens :: Lens' NodeOSStats Bytes
+nodeOSStatsSwapTotalLens = lens nodeOSSwapTotal (\x y -> x {nodeOSSwapTotal = y})
+
+nodeOSStatsSwapFreeLens :: Lens' NodeOSStats Bytes
+nodeOSStatsSwapFreeLens = lens nodeOSSwapFree (\x y -> x {nodeOSSwapFree = y})
+
+nodeOSStatsSwapUsedLens :: Lens' NodeOSStats Bytes
+nodeOSStatsSwapUsedLens = lens nodeOSSwapUsed (\x y -> x {nodeOSSwapUsed = y})
+
+data LoadAvgs = LoadAvgs
+  { loadAvg1Min :: Double,
+    loadAvg5Min :: Double,
+    loadAvg15Min :: Double
+  }
+  deriving stock (Eq, Show)
+
+loadAvgs1MinLens :: Lens' LoadAvgs Double
+loadAvgs1MinLens = lens loadAvg1Min (\x y -> x {loadAvg1Min = y})
+
+loadAvgs5MinLens :: Lens' LoadAvgs Double
+loadAvgs5MinLens = lens loadAvg5Min (\x y -> x {loadAvg5Min = y})
+
+loadAvgs15MinLens :: Lens' LoadAvgs Double
+loadAvgs15MinLens = lens loadAvg15Min (\x y -> x {loadAvg15Min = y})
+
+data NodeIndicesStats = NodeIndicesStats
+  { nodeIndicesStatsRecoveryThrottleTime :: Maybe NominalDiffTime,
+    nodeIndicesStatsRecoveryCurrentAsTarget :: Maybe Int,
+    nodeIndicesStatsRecoveryCurrentAsSource :: Maybe Int,
+    nodeIndicesStatsQueryCacheMisses :: Maybe Int,
+    nodeIndicesStatsQueryCacheHits :: Maybe Int,
+    nodeIndicesStatsQueryCacheEvictions :: Maybe Int,
+    nodeIndicesStatsQueryCacheSize :: Maybe Bytes,
+    nodeIndicesStatsSuggestCurrent :: Maybe Int,
+    nodeIndicesStatsSuggestTime :: Maybe NominalDiffTime,
+    nodeIndicesStatsSuggestTotal :: Maybe Int,
+    nodeIndicesStatsTranslogSize :: Bytes,
+    nodeIndicesStatsTranslogOps :: Int,
+    nodeIndicesStatsSegFixedBitSetMemory :: Maybe Bytes,
+    nodeIndicesStatsSegVersionMapMemory :: Bytes,
+    nodeIndicesStatsSegIndexWriterMaxMemory :: Maybe Bytes,
+    nodeIndicesStatsSegIndexWriterMemory :: Bytes,
+    nodeIndicesStatsSegMemory :: Bytes,
+    nodeIndicesStatsSegCount :: Int,
+    nodeIndicesStatsCompletionSize :: Bytes,
+    nodeIndicesStatsPercolateQueries :: Maybe Int,
+    nodeIndicesStatsPercolateMemory :: Maybe Bytes,
+    nodeIndicesStatsPercolateCurrent :: Maybe Int,
+    nodeIndicesStatsPercolateTime :: Maybe NominalDiffTime,
+    nodeIndicesStatsPercolateTotal :: Maybe Int,
+    nodeIndicesStatsFieldDataEvictions :: Int,
+    nodeIndicesStatsFieldDataMemory :: Bytes,
+    nodeIndicesStatsWarmerTotalTime :: NominalDiffTime,
+    nodeIndicesStatsWarmerTotal :: Int,
+    nodeIndicesStatsWarmerCurrent :: Int,
+    nodeIndicesStatsFlushTotalTime :: NominalDiffTime,
+    nodeIndicesStatsFlushTotal :: Int,
+    nodeIndicesStatsRefreshTotalTime :: NominalDiffTime,
+    nodeIndicesStatsRefreshTotal :: Int,
+    nodeIndicesStatsMergesTotalSize :: Bytes,
+    nodeIndicesStatsMergesTotalDocs :: Int,
+    nodeIndicesStatsMergesTotalTime :: NominalDiffTime,
+    nodeIndicesStatsMergesTotal :: Int,
+    nodeIndicesStatsMergesCurrentSize :: Bytes,
+    nodeIndicesStatsMergesCurrentDocs :: Int,
+    nodeIndicesStatsMergesCurrent :: Int,
+    nodeIndicesStatsSearchFetchCurrent :: Int,
+    nodeIndicesStatsSearchFetchTime :: NominalDiffTime,
+    nodeIndicesStatsSearchFetchTotal :: Int,
+    nodeIndicesStatsSearchQueryCurrent :: Int,
+    nodeIndicesStatsSearchQueryTime :: NominalDiffTime,
+    nodeIndicesStatsSearchQueryTotal :: Int,
+    nodeIndicesStatsSearchOpenContexts :: Int,
+    nodeIndicesStatsGetCurrent :: Int,
+    nodeIndicesStatsGetMissingTime :: NominalDiffTime,
+    nodeIndicesStatsGetMissingTotal :: Int,
+    nodeIndicesStatsGetExistsTime :: NominalDiffTime,
+    nodeIndicesStatsGetExistsTotal :: Int,
+    nodeIndicesStatsGetTime :: NominalDiffTime,
+    nodeIndicesStatsGetTotal :: Int,
+    nodeIndicesStatsIndexingThrottleTime :: Maybe NominalDiffTime,
+    nodeIndicesStatsIndexingIsThrottled :: Maybe Bool,
+    nodeIndicesStatsIndexingNoopUpdateTotal :: Maybe Int,
+    nodeIndicesStatsIndexingDeleteCurrent :: Int,
+    nodeIndicesStatsIndexingDeleteTime :: NominalDiffTime,
+    nodeIndicesStatsIndexingDeleteTotal :: Int,
+    nodeIndicesStatsIndexingIndexCurrent :: Int,
+    nodeIndicesStatsIndexingIndexTime :: NominalDiffTime,
+    nodeIndicesStatsIndexingTotal :: Int,
+    nodeIndicesStatsStoreThrottleTime :: Maybe NominalDiffTime,
+    nodeIndicesStatsStoreSize :: Bytes,
+    nodeIndicesStatsDocsDeleted :: Int,
+    nodeIndicesStatsDocsCount :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeIndicesStatsRecoveryThrottleTimeLens :: Lens' NodeIndicesStats (Maybe NominalDiffTime)
+nodeIndicesStatsRecoveryThrottleTimeLens = lens nodeIndicesStatsRecoveryThrottleTime (\x y -> x {nodeIndicesStatsRecoveryThrottleTime = y})
+
+nodeIndicesStatsRecoveryCurrentAsTargetLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsRecoveryCurrentAsTargetLens = lens nodeIndicesStatsRecoveryCurrentAsTarget (\x y -> x {nodeIndicesStatsRecoveryCurrentAsTarget = y})
+
+nodeIndicesStatsRecoveryCurrentAsSourceLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsRecoveryCurrentAsSourceLens = lens nodeIndicesStatsRecoveryCurrentAsSource (\x y -> x {nodeIndicesStatsRecoveryCurrentAsSource = y})
+
+nodeIndicesStatsQueryCacheMissesLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsQueryCacheMissesLens = lens nodeIndicesStatsQueryCacheMisses (\x y -> x {nodeIndicesStatsQueryCacheMisses = y})
+
+nodeIndicesStatsQueryCacheHitsLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsQueryCacheHitsLens = lens nodeIndicesStatsQueryCacheHits (\x y -> x {nodeIndicesStatsQueryCacheHits = y})
+
+nodeIndicesStatsQueryCacheEvictionsLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsQueryCacheEvictionsLens = lens nodeIndicesStatsQueryCacheEvictions (\x y -> x {nodeIndicesStatsQueryCacheEvictions = y})
+
+nodeIndicesStatsQueryCacheSizeLens :: Lens' NodeIndicesStats (Maybe Bytes)
+nodeIndicesStatsQueryCacheSizeLens = lens nodeIndicesStatsQueryCacheSize (\x y -> x {nodeIndicesStatsQueryCacheSize = y})
+
+nodeIndicesStatsSuggestCurrentLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsSuggestCurrentLens = lens nodeIndicesStatsSuggestCurrent (\x y -> x {nodeIndicesStatsSuggestCurrent = y})
+
+nodeIndicesStatsSuggestTimeLens :: Lens' NodeIndicesStats (Maybe NominalDiffTime)
+nodeIndicesStatsSuggestTimeLens = lens nodeIndicesStatsSuggestTime (\x y -> x {nodeIndicesStatsSuggestTime = y})
+
+nodeIndicesStatsSuggestTotalLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsSuggestTotalLens = lens nodeIndicesStatsSuggestTotal (\x y -> x {nodeIndicesStatsSuggestTotal = y})
+
+nodeIndicesStatsTranslogSizeLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsTranslogSizeLens = lens nodeIndicesStatsTranslogSize (\x y -> x {nodeIndicesStatsTranslogSize = y})
+
+nodeIndicesStatsTranslogOpsLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsTranslogOpsLens = lens nodeIndicesStatsTranslogOps (\x y -> x {nodeIndicesStatsTranslogOps = y})
+
+nodeIndicesStatsSegFixedBitSetMemoryLens :: Lens' NodeIndicesStats (Maybe Bytes)
+nodeIndicesStatsSegFixedBitSetMemoryLens = lens nodeIndicesStatsSegFixedBitSetMemory (\x y -> x {nodeIndicesStatsSegFixedBitSetMemory = y})
+
+nodeIndicesStatsSegVersionMapMemoryLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsSegVersionMapMemoryLens = lens nodeIndicesStatsSegVersionMapMemory (\x y -> x {nodeIndicesStatsSegVersionMapMemory = y})
+
+nodeIndicesStatsSegIndexWriterMaxMemoryLens :: Lens' NodeIndicesStats (Maybe Bytes)
+nodeIndicesStatsSegIndexWriterMaxMemoryLens = lens nodeIndicesStatsSegIndexWriterMaxMemory (\x y -> x {nodeIndicesStatsSegIndexWriterMaxMemory = y})
+
+nodeIndicesStatsSegIndexWriterMemoryLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsSegIndexWriterMemoryLens = lens nodeIndicesStatsSegIndexWriterMemory (\x y -> x {nodeIndicesStatsSegIndexWriterMemory = y})
+
+nodeIndicesStatsSegMemoryLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsSegMemoryLens = lens nodeIndicesStatsSegMemory (\x y -> x {nodeIndicesStatsSegMemory = y})
+
+nodeIndicesStatsSegCountLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSegCountLens = lens nodeIndicesStatsSegCount (\x y -> x {nodeIndicesStatsSegCount = y})
+
+nodeIndicesStatsCompletionSizeLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsCompletionSizeLens = lens nodeIndicesStatsCompletionSize (\x y -> x {nodeIndicesStatsCompletionSize = y})
+
+nodeIndicesStatsPercolateQueriesLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsPercolateQueriesLens = lens nodeIndicesStatsPercolateQueries (\x y -> x {nodeIndicesStatsPercolateQueries = y})
+
+nodeIndicesStatsPercolateMemoryLens :: Lens' NodeIndicesStats (Maybe Bytes)
+nodeIndicesStatsPercolateMemoryLens = lens nodeIndicesStatsPercolateMemory (\x y -> x {nodeIndicesStatsPercolateMemory = y})
+
+nodeIndicesStatsPercolateCurrentLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsPercolateCurrentLens = lens nodeIndicesStatsPercolateCurrent (\x y -> x {nodeIndicesStatsPercolateCurrent = y})
+
+nodeIndicesStatsPercolateTimeLens :: Lens' NodeIndicesStats (Maybe NominalDiffTime)
+nodeIndicesStatsPercolateTimeLens = lens nodeIndicesStatsPercolateTime (\x y -> x {nodeIndicesStatsPercolateTime = y})
+
+nodeIndicesStatsPercolateTotalLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsPercolateTotalLens = lens nodeIndicesStatsPercolateTotal (\x y -> x {nodeIndicesStatsPercolateTotal = y})
+
+nodeIndicesStatsFieldDataEvictionsLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsFieldDataEvictionsLens = lens nodeIndicesStatsFieldDataEvictions (\x y -> x {nodeIndicesStatsFieldDataEvictions = y})
+
+nodeIndicesStatsFieldDataMemoryLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsFieldDataMemoryLens = lens nodeIndicesStatsFieldDataMemory (\x y -> x {nodeIndicesStatsFieldDataMemory = y})
+
+nodeIndicesStatsWarmerTotalTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsWarmerTotalTimeLens = lens nodeIndicesStatsWarmerTotalTime (\x y -> x {nodeIndicesStatsWarmerTotalTime = y})
+
+nodeIndicesStatsWarmerTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsWarmerTotalLens = lens nodeIndicesStatsWarmerTotal (\x y -> x {nodeIndicesStatsWarmerTotal = y})
+
+nodeIndicesStatsWarmerCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsWarmerCurrentLens = lens nodeIndicesStatsWarmerCurrent (\x y -> x {nodeIndicesStatsWarmerCurrent = y})
+
+nodeIndicesStatsFlushTotalTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsFlushTotalTimeLens = lens nodeIndicesStatsFlushTotalTime (\x y -> x {nodeIndicesStatsFlushTotalTime = y})
+
+nodeIndicesStatsFlushTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsFlushTotalLens = lens nodeIndicesStatsFlushTotal (\x y -> x {nodeIndicesStatsFlushTotal = y})
+
+nodeIndicesStatsRefreshTotalTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsRefreshTotalTimeLens = lens nodeIndicesStatsRefreshTotalTime (\x y -> x {nodeIndicesStatsRefreshTotalTime = y})
+
+nodeIndicesStatsRefreshTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsRefreshTotalLens = lens nodeIndicesStatsRefreshTotal (\x y -> x {nodeIndicesStatsRefreshTotal = y})
+
+nodeIndicesStatsMergesTotalSizeLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsMergesTotalSizeLens = lens nodeIndicesStatsMergesTotalSize (\x y -> x {nodeIndicesStatsMergesTotalSize = y})
+
+nodeIndicesStatsMergesTotalDocsLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsMergesTotalDocsLens = lens nodeIndicesStatsMergesTotalDocs (\x y -> x {nodeIndicesStatsMergesTotalDocs = y})
+
+nodeIndicesStatsMergesTotalTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsMergesTotalTimeLens = lens nodeIndicesStatsMergesTotalTime (\x y -> x {nodeIndicesStatsMergesTotalTime = y})
+
+nodeIndicesStatsMergesTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsMergesTotalLens = lens nodeIndicesStatsMergesTotal (\x y -> x {nodeIndicesStatsMergesTotal = y})
+
+nodeIndicesStatsMergesCurrentSizeLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsMergesCurrentSizeLens = lens nodeIndicesStatsMergesCurrentSize (\x y -> x {nodeIndicesStatsMergesCurrentSize = y})
+
+nodeIndicesStatsMergesCurrentDocsLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsMergesCurrentDocsLens = lens nodeIndicesStatsMergesCurrentDocs (\x y -> x {nodeIndicesStatsMergesCurrentDocs = y})
+
+nodeIndicesStatsMergesCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsMergesCurrentLens = lens nodeIndicesStatsMergesCurrent (\x y -> x {nodeIndicesStatsMergesCurrent = y})
+
+nodeIndicesStatsSearchFetchCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSearchFetchCurrentLens = lens nodeIndicesStatsSearchFetchCurrent (\x y -> x {nodeIndicesStatsSearchFetchCurrent = y})
+
+nodeIndicesStatsSearchFetchTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsSearchFetchTimeLens = lens nodeIndicesStatsSearchFetchTime (\x y -> x {nodeIndicesStatsSearchFetchTime = y})
+
+nodeIndicesStatsSearchFetchTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSearchFetchTotalLens = lens nodeIndicesStatsSearchFetchTotal (\x y -> x {nodeIndicesStatsSearchFetchTotal = y})
+
+nodeIndicesStatsSearchQueryCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSearchQueryCurrentLens = lens nodeIndicesStatsSearchQueryCurrent (\x y -> x {nodeIndicesStatsSearchQueryCurrent = y})
+
+nodeIndicesStatsSearchQueryTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsSearchQueryTimeLens = lens nodeIndicesStatsSearchQueryTime (\x y -> x {nodeIndicesStatsSearchQueryTime = y})
+
+nodeIndicesStatsSearchQueryTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSearchQueryTotalLens = lens nodeIndicesStatsSearchQueryTotal (\x y -> x {nodeIndicesStatsSearchQueryTotal = y})
+
+nodeIndicesStatsSearchOpenContextsLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsSearchOpenContextsLens = lens nodeIndicesStatsSearchOpenContexts (\x y -> x {nodeIndicesStatsSearchOpenContexts = y})
+
+nodeIndicesStatsGetCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsGetCurrentLens = lens nodeIndicesStatsGetCurrent (\x y -> x {nodeIndicesStatsGetCurrent = y})
+
+nodeIndicesStatsGetMissingTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsGetMissingTimeLens = lens nodeIndicesStatsGetMissingTime (\x y -> x {nodeIndicesStatsGetMissingTime = y})
+
+nodeIndicesStatsGetMissingTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsGetMissingTotalLens = lens nodeIndicesStatsGetMissingTotal (\x y -> x {nodeIndicesStatsGetMissingTotal = y})
+
+nodeIndicesStatsGetExistsTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsGetExistsTimeLens = lens nodeIndicesStatsGetExistsTime (\x y -> x {nodeIndicesStatsGetExistsTime = y})
+
+nodeIndicesStatsGetExistsTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsGetExistsTotalLens = lens nodeIndicesStatsGetExistsTotal (\x y -> x {nodeIndicesStatsGetExistsTotal = y})
+
+nodeIndicesStatsGetTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsGetTimeLens = lens nodeIndicesStatsGetTime (\x y -> x {nodeIndicesStatsGetTime = y})
+
+nodeIndicesStatsGetTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsGetTotalLens = lens nodeIndicesStatsGetTotal (\x y -> x {nodeIndicesStatsGetTotal = y})
+
+nodeIndicesStatsIndexingThrottleTimeLens :: Lens' NodeIndicesStats (Maybe NominalDiffTime)
+nodeIndicesStatsIndexingThrottleTimeLens = lens nodeIndicesStatsIndexingThrottleTime (\x y -> x {nodeIndicesStatsIndexingThrottleTime = y})
+
+nodeIndicesStatsIndexingIsThrottledLens :: Lens' NodeIndicesStats (Maybe Bool)
+nodeIndicesStatsIndexingIsThrottledLens = lens nodeIndicesStatsIndexingIsThrottled (\x y -> x {nodeIndicesStatsIndexingIsThrottled = y})
+
+nodeIndicesStatsIndexingNoopUpdateTotalLens :: Lens' NodeIndicesStats (Maybe Int)
+nodeIndicesStatsIndexingNoopUpdateTotalLens = lens nodeIndicesStatsIndexingNoopUpdateTotal (\x y -> x {nodeIndicesStatsIndexingNoopUpdateTotal = y})
+
+nodeIndicesStatsIndexingDeleteCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsIndexingDeleteCurrentLens = lens nodeIndicesStatsIndexingDeleteCurrent (\x y -> x {nodeIndicesStatsIndexingDeleteCurrent = y})
+
+nodeIndicesStatsIndexingDeleteTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsIndexingDeleteTimeLens = lens nodeIndicesStatsIndexingDeleteTime (\x y -> x {nodeIndicesStatsIndexingDeleteTime = y})
+
+nodeIndicesStatsIndexingDeleteTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsIndexingDeleteTotalLens = lens nodeIndicesStatsIndexingDeleteTotal (\x y -> x {nodeIndicesStatsIndexingDeleteTotal = y})
+
+nodeIndicesStatsIndexingIndexCurrentLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsIndexingIndexCurrentLens = lens nodeIndicesStatsIndexingIndexCurrent (\x y -> x {nodeIndicesStatsIndexingIndexCurrent = y})
+
+nodeIndicesStatsIndexingIndexTimeLens :: Lens' NodeIndicesStats NominalDiffTime
+nodeIndicesStatsIndexingIndexTimeLens = lens nodeIndicesStatsIndexingIndexTime (\x y -> x {nodeIndicesStatsIndexingIndexTime = y})
+
+nodeIndicesStatsIndexingTotalLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsIndexingTotalLens = lens nodeIndicesStatsIndexingTotal (\x y -> x {nodeIndicesStatsIndexingTotal = y})
+
+nodeIndicesStatsStoreThrottleTimeLens :: Lens' NodeIndicesStats (Maybe NominalDiffTime)
+nodeIndicesStatsStoreThrottleTimeLens = lens nodeIndicesStatsStoreThrottleTime (\x y -> x {nodeIndicesStatsStoreThrottleTime = y})
+
+nodeIndicesStatsStoreSizeLens :: Lens' NodeIndicesStats Bytes
+nodeIndicesStatsStoreSizeLens = lens nodeIndicesStatsStoreSize (\x y -> x {nodeIndicesStatsStoreSize = y})
+
+nodeIndicesStatsDocsDeletedLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsDocsDeletedLens = lens nodeIndicesStatsDocsDeleted (\x y -> x {nodeIndicesStatsDocsDeleted = y})
+
+nodeIndicesStatsDocsCountLens :: Lens' NodeIndicesStats Int
+nodeIndicesStatsDocsCountLens = lens nodeIndicesStatsDocsCount (\x y -> x {nodeIndicesStatsDocsCount = y})
+
+-- | A quirky address format used throughout Elasticsearch. An example
+-- would be inet[/1.1.1.1:9200]. inet may be a placeholder for a
+-- <https://en.wikipedia.org/wiki/Fully_qualified_domain_name FQDN>.
+newtype EsAddress = EsAddress {esAddress :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+-- | Typically a 7 character hex string.
+newtype BuildHash = BuildHash {buildHash :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON, ToJSON)
+
+newtype PluginName = PluginName {pluginName :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+data NodeInfo = NodeInfo
+  { nodeInfoHTTPAddress :: Maybe EsAddress,
+    nodeInfoBuild :: BuildHash,
+    nodeInfoESVersion :: VersionNumber,
+    nodeInfoIP :: Server,
+    nodeInfoHost :: Server,
+    nodeInfoTransportAddress :: EsAddress,
+    nodeInfoName :: NodeName,
+    nodeInfoFullId :: FullNodeId,
+    nodeInfoPlugins :: [NodePluginInfo],
+    nodeInfoHTTP :: NodeHTTPInfo,
+    nodeInfoTransport :: NodeTransportInfo,
+    nodeInfoNetwork :: Maybe NodeNetworkInfo,
+    nodeInfoThreadPool :: Map Text NodeThreadPoolInfo,
+    nodeInfoJVM :: NodeJVMInfo,
+    nodeInfoProcess :: NodeProcessInfo,
+    nodeInfoOS :: NodeOSInfo,
+    -- | The members of the settings objects are not consistent,
+    -- dependent on plugins, etc.
+    nodeInfoSettings :: Object
+  }
+  deriving stock (Eq, Show)
+
+nodeInfoHTTPAddressLens :: Lens' NodeInfo (Maybe EsAddress)
+nodeInfoHTTPAddressLens = lens nodeInfoHTTPAddress (\x y -> x {nodeInfoHTTPAddress = y})
+
+nodeInfoBuildLens :: Lens' NodeInfo BuildHash
+nodeInfoBuildLens = lens nodeInfoBuild (\x y -> x {nodeInfoBuild = y})
+
+nodeInfoESVersionLens :: Lens' NodeInfo VersionNumber
+nodeInfoESVersionLens = lens nodeInfoESVersion (\x y -> x {nodeInfoESVersion = y})
+
+nodeInfoIPLens :: Lens' NodeInfo Server
+nodeInfoIPLens = lens nodeInfoIP (\x y -> x {nodeInfoIP = y})
+
+nodeInfoHostLens :: Lens' NodeInfo Server
+nodeInfoHostLens = lens nodeInfoHost (\x y -> x {nodeInfoHost = y})
+
+nodeInfoTransportAddressLens :: Lens' NodeInfo EsAddress
+nodeInfoTransportAddressLens = lens nodeInfoTransportAddress (\x y -> x {nodeInfoTransportAddress = y})
+
+nodeInfoNameLens :: Lens' NodeInfo NodeName
+nodeInfoNameLens = lens nodeInfoName (\x y -> x {nodeInfoName = y})
+
+nodeInfoFullIdLens :: Lens' NodeInfo FullNodeId
+nodeInfoFullIdLens = lens nodeInfoFullId (\x y -> x {nodeInfoFullId = y})
+
+nodeInfoPluginsLens :: Lens' NodeInfo [NodePluginInfo]
+nodeInfoPluginsLens = lens nodeInfoPlugins (\x y -> x {nodeInfoPlugins = y})
+
+nodeInfoHTTPLens :: Lens' NodeInfo NodeHTTPInfo
+nodeInfoHTTPLens = lens nodeInfoHTTP (\x y -> x {nodeInfoHTTP = y})
+
+nodeInfoTransportLens :: Lens' NodeInfo NodeTransportInfo
+nodeInfoTransportLens = lens nodeInfoTransport (\x y -> x {nodeInfoTransport = y})
+
+nodeInfoNetworkLens :: Lens' NodeInfo (Maybe NodeNetworkInfo)
+nodeInfoNetworkLens = lens nodeInfoNetwork (\x y -> x {nodeInfoNetwork = y})
+
+nodeInfoThreadPoolLens :: Lens' NodeInfo (Map Text NodeThreadPoolInfo)
+nodeInfoThreadPoolLens = lens nodeInfoThreadPool (\x y -> x {nodeInfoThreadPool = y})
+
+nodeInfoJVMLens :: Lens' NodeInfo NodeJVMInfo
+nodeInfoJVMLens = lens nodeInfoJVM (\x y -> x {nodeInfoJVM = y})
+
+nodeInfoProcessLens :: Lens' NodeInfo NodeProcessInfo
+nodeInfoProcessLens = lens nodeInfoProcess (\x y -> x {nodeInfoProcess = y})
+
+nodeInfoOSLens :: Lens' NodeInfo NodeOSInfo
+nodeInfoOSLens = lens nodeInfoOS (\x y -> x {nodeInfoOS = y})
+
+nodeInfoSettingsLens :: Lens' NodeInfo Object
+nodeInfoSettingsLens = lens nodeInfoSettings (\x y -> x {nodeInfoSettings = y})
+
+data NodePluginInfo = NodePluginInfo
+  { -- | Is this a site plugin?
+    nodePluginSite :: Maybe Bool,
+    -- | Is this plugin running on the JVM
+    nodePluginJVM :: Maybe Bool,
+    nodePluginDescription :: Text,
+    nodePluginVersion :: MaybeNA VersionNumber,
+    nodePluginName :: PluginName
+  }
+  deriving stock (Eq, Show)
+
+nodePluginSiteLens :: Lens' NodePluginInfo (Maybe Bool)
+nodePluginSiteLens = lens nodePluginSite (\x y -> x {nodePluginSite = y})
+
+-- \| Is this plugin running on the JVM
+nodePluginInfoJVMLens :: Lens' NodePluginInfo (Maybe Bool)
+nodePluginInfoJVMLens = lens nodePluginJVM (\x y -> x {nodePluginJVM = y})
+
+nodePluginInfoDescriptionLens :: Lens' NodePluginInfo Text
+nodePluginInfoDescriptionLens = lens nodePluginDescription (\x y -> x {nodePluginDescription = y})
+
+nodePluginInfoVersionLens :: Lens' NodePluginInfo (MaybeNA VersionNumber)
+nodePluginInfoVersionLens = lens nodePluginVersion (\x y -> x {nodePluginVersion = y})
+
+nodePluginInfoNameLens :: Lens' NodePluginInfo PluginName
+nodePluginInfoNameLens = lens nodePluginName (\x y -> x {nodePluginName = y})
+
+data NodeHTTPInfo = NodeHTTPInfo
+  { nodeHTTPMaxContentLength :: Bytes,
+    nodeHTTPpublishAddress :: EsAddress,
+    nodeHTTPbound_address :: [EsAddress]
+  }
+  deriving stock (Eq, Show)
+
+nodeHTTPInfoMaxContentLengthLens :: Lens' NodeHTTPInfo Bytes
+nodeHTTPInfoMaxContentLengthLens = lens nodeHTTPMaxContentLength (\x y -> x {nodeHTTPMaxContentLength = y})
+
+nodeHTTPInfopublishAddressLens :: Lens' NodeHTTPInfo EsAddress
+nodeHTTPInfopublishAddressLens = lens nodeHTTPpublishAddress (\x y -> x {nodeHTTPpublishAddress = y})
+
+nodeHTTPInfoBoundAddressesLens :: Lens' NodeHTTPInfo [EsAddress]
+nodeHTTPInfoBoundAddressesLens = lens nodeHTTPbound_address (\x y -> x {nodeHTTPbound_address = y})
+
+data NodeTransportInfo = NodeTransportInfo
+  { nodeTransportProfiles :: [BoundTransportAddress],
+    nodeTransportPublishAddress :: EsAddress,
+    nodeTransportBoundAddress :: [EsAddress]
+  }
+  deriving stock (Eq, Show)
+
+nodeTransportInfoProfilesLens :: Lens' NodeTransportInfo [BoundTransportAddress]
+nodeTransportInfoProfilesLens = lens nodeTransportProfiles (\x y -> x {nodeTransportProfiles = y})
+
+nodeTransportInfoPublishAddressLens :: Lens' NodeTransportInfo EsAddress
+nodeTransportInfoPublishAddressLens = lens nodeTransportPublishAddress (\x y -> x {nodeTransportPublishAddress = y})
+
+nodeTransportInfoBoundAddressLens :: Lens' NodeTransportInfo [EsAddress]
+nodeTransportInfoBoundAddressLens = lens nodeTransportBoundAddress (\x y -> x {nodeTransportBoundAddress = y})
+
+data BoundTransportAddress = BoundTransportAddress
+  { publishAddress :: EsAddress,
+    boundAddress :: [EsAddress]
+  }
+  deriving stock (Eq, Show)
+
+boundTransportAddressPublishAddressLens :: Lens' BoundTransportAddress EsAddress
+boundTransportAddressPublishAddressLens = lens publishAddress (\x y -> x {publishAddress = y})
+
+boundTransportAddressBoundAddressesLens :: Lens' BoundTransportAddress [EsAddress]
+boundTransportAddressBoundAddressesLens = lens boundAddress (\x y -> x {boundAddress = y})
+
+data NodeNetworkInfo = NodeNetworkInfo
+  { nodeNetworkPrimaryInterface :: NodeNetworkInterface,
+    nodeNetworkRefreshInterval :: NominalDiffTime
+  }
+  deriving stock (Eq, Show)
+
+nodeNetworkInfoPrimaryInterfaceLens :: Lens' NodeNetworkInfo NodeNetworkInterface
+nodeNetworkInfoPrimaryInterfaceLens = lens nodeNetworkPrimaryInterface (\x y -> x {nodeNetworkPrimaryInterface = y})
+
+nodeNetworkInfoRefreshIntervalLens :: Lens' NodeNetworkInfo NominalDiffTime
+nodeNetworkInfoRefreshIntervalLens = lens nodeNetworkRefreshInterval (\x y -> x {nodeNetworkRefreshInterval = y})
+
+newtype MacAddress = MacAddress {macAddress :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+newtype NetworkInterfaceName = NetworkInterfaceName {networkInterfaceName :: Text}
+  deriving newtype (Eq, Ord, Show, FromJSON)
+
+data NodeNetworkInterface = NodeNetworkInterface
+  { nodeNetIfaceMacAddress :: MacAddress,
+    nodeNetIfaceName :: NetworkInterfaceName,
+    nodeNetIfaceAddress :: Server
+  }
+  deriving stock (Eq, Show)
+
+nodeNetworkInterfaceMacAddressLens :: Lens' NodeNetworkInterface MacAddress
+nodeNetworkInterfaceMacAddressLens = lens nodeNetIfaceMacAddress (\x y -> x {nodeNetIfaceMacAddress = y})
+
+nodeNetworkInterfaceNameLens :: Lens' NodeNetworkInterface NetworkInterfaceName
+nodeNetworkInterfaceNameLens = lens nodeNetIfaceName (\x y -> x {nodeNetIfaceName = y})
+
+nodeNetworkInterfaceAddressLens :: Lens' NodeNetworkInterface Server
+nodeNetworkInterfaceAddressLens = lens nodeNetIfaceAddress (\x y -> x {nodeNetIfaceAddress = y})
+
+data ThreadPool = ThreadPool
+  { nodeThreadPoolName :: Text,
+    nodeThreadPoolInfo :: NodeThreadPoolInfo
+  }
+  deriving stock (Eq, Show)
+
+threadPoolNodeThreadPoolNameLens :: Lens' ThreadPool Text
+threadPoolNodeThreadPoolNameLens = lens nodeThreadPoolName (\x y -> x {nodeThreadPoolName = y})
+
+threadPoolNodeThreadPoolInfoLens :: Lens' ThreadPool NodeThreadPoolInfo
+threadPoolNodeThreadPoolInfoLens = lens nodeThreadPoolInfo (\x y -> x {nodeThreadPoolInfo = y})
+
+data NodeThreadPoolInfo = NodeThreadPoolInfo
+  { nodeThreadPoolQueueSize :: ThreadPoolSize,
+    nodeThreadPoolKeepalive :: Maybe NominalDiffTime,
+    nodeThreadPoolMin :: Maybe Int,
+    nodeThreadPoolMax :: Maybe Int,
+    nodeThreadPoolType :: ThreadPoolType
+  }
+  deriving stock (Eq, Show)
+
+nodeThreadPoolInfoQueueSizeLens :: Lens' NodeThreadPoolInfo ThreadPoolSize
+nodeThreadPoolInfoQueueSizeLens = lens nodeThreadPoolQueueSize (\x y -> x {nodeThreadPoolQueueSize = y})
+
+nodeThreadPoolInfoKeepaliveLens :: Lens' NodeThreadPoolInfo (Maybe NominalDiffTime)
+nodeThreadPoolInfoKeepaliveLens = lens nodeThreadPoolKeepalive (\x y -> x {nodeThreadPoolKeepalive = y})
+
+nodeThreadPoolInfoMinLens :: Lens' NodeThreadPoolInfo (Maybe Int)
+nodeThreadPoolInfoMinLens = lens nodeThreadPoolMin (\x y -> x {nodeThreadPoolMin = y})
+
+nodeThreadPoolInfoMaxLens :: Lens' NodeThreadPoolInfo (Maybe Int)
+nodeThreadPoolInfoMaxLens = lens nodeThreadPoolMax (\x y -> x {nodeThreadPoolMax = y})
+
+nodeThreadPoolInfoTypeLens :: Lens' NodeThreadPoolInfo ThreadPoolType
+nodeThreadPoolInfoTypeLens = lens nodeThreadPoolType (\x y -> x {nodeThreadPoolType = y})
+
+data ThreadPoolSize
+  = ThreadPoolBounded Int
+  | ThreadPoolUnbounded
+  deriving stock (Eq, Show)
+
+threadPoolSizeBoundedPrism :: Prism' ThreadPoolSize Int
+threadPoolSizeBoundedPrism = prism ThreadPoolBounded extract
+  where
+    extract s =
+      case s of
+        ThreadPoolBounded x -> Right x
+        _ -> Left s
+
+data ThreadPoolType
+  = ThreadPoolScaling
+  | ThreadPoolFixed
+  | ThreadPoolCached
+  | ThreadPoolFixedAutoQueueSize
+  deriving stock (Eq, Show)
+
+data NodeJVMInfo = NodeJVMInfo
+  { nodeJVMInfoMemoryPools :: [JVMMemoryPool],
+    nodeJVMInfoMemoryPoolsGCCollectors :: [JVMGCCollector],
+    nodeJVMInfoMemoryInfo :: JVMMemoryInfo,
+    nodeJVMInfoStartTime :: UTCTime,
+    nodeJVMInfoVMVendor :: Text,
+    -- | JVM doesn't seme to follow normal version conventions
+    nodeJVMVMVersion :: VersionNumber,
+    nodeJVMVMName :: Text,
+    nodeJVMVersion :: JVMVersion,
+    nodeJVMPID :: PID
+  }
+  deriving stock (Eq, Show)
+
+nodeJVMInfoMemoryPoolsLens :: Lens' NodeJVMInfo [JVMMemoryPool]
+nodeJVMInfoMemoryPoolsLens = lens nodeJVMInfoMemoryPools (\x y -> x {nodeJVMInfoMemoryPools = y})
+
+nodeJVMInfoMemoryPoolsGCCollectorsLens :: Lens' NodeJVMInfo [JVMGCCollector]
+nodeJVMInfoMemoryPoolsGCCollectorsLens = lens nodeJVMInfoMemoryPoolsGCCollectors (\x y -> x {nodeJVMInfoMemoryPoolsGCCollectors = y})
+
+nodeJVMInfoMemoryInfoLens :: Lens' NodeJVMInfo JVMMemoryInfo
+nodeJVMInfoMemoryInfoLens = lens nodeJVMInfoMemoryInfo (\x y -> x {nodeJVMInfoMemoryInfo = y})
+
+nodeJVMInfoStartTimeLens :: Lens' NodeJVMInfo UTCTime
+nodeJVMInfoStartTimeLens = lens nodeJVMInfoStartTime (\x y -> x {nodeJVMInfoStartTime = y})
+
+nodeJVMInfoVMVendorLens :: Lens' NodeJVMInfo Text
+nodeJVMInfoVMVendorLens = lens nodeJVMInfoVMVendor (\x y -> x {nodeJVMInfoVMVendor = y})
+
+nodeJVMInfoVMVersionLens :: Lens' NodeJVMInfo VersionNumber
+nodeJVMInfoVMVersionLens = lens nodeJVMVMVersion (\x y -> x {nodeJVMVMVersion = y})
+
+nodeJVMInfoVMNameLens :: Lens' NodeJVMInfo Text
+nodeJVMInfoVMNameLens = lens nodeJVMVMName (\x y -> x {nodeJVMVMName = y})
+
+nodeJVMInfoVersionLens :: Lens' NodeJVMInfo JVMVersion
+nodeJVMInfoVersionLens = lens nodeJVMVersion (\x y -> x {nodeJVMVersion = y})
+
+nodeJVMInfoPIDLens :: Lens' NodeJVMInfo PID
+nodeJVMInfoPIDLens = lens nodeJVMPID (\x y -> x {nodeJVMPID = y})
+
+-- | We cannot parse JVM version numbers and we're not going to try.
+newtype JVMVersion = JVMVersion {unJVMVersion :: Text}
+  deriving stock (Eq, Show)
+
+instance FromJSON JVMVersion where
+  parseJSON = withText "JVMVersion" (pure . JVMVersion)
+
+data JVMMemoryInfo = JVMMemoryInfo
+  { jvmMemoryInfoDirectMax :: Bytes,
+    jvmMemoryInfoNonHeapMax :: Bytes,
+    jvmMemoryInfoNonHeapInit :: Bytes,
+    jvmMemoryInfoHeapMax :: Bytes,
+    jvmMemoryInfoHeapInit :: Bytes
+  }
+  deriving stock (Eq, Show)
+
+jvmMemoryInfoDirectMaxLens :: Lens' JVMMemoryInfo Bytes
+jvmMemoryInfoDirectMaxLens = lens jvmMemoryInfoDirectMax (\x y -> x {jvmMemoryInfoDirectMax = y})
+
+jvmMemoryInfoNonHeapMaxLens :: Lens' JVMMemoryInfo Bytes
+jvmMemoryInfoNonHeapMaxLens = lens jvmMemoryInfoNonHeapMax (\x y -> x {jvmMemoryInfoNonHeapMax = y})
+
+jvmMemoryInfoNonHeapInitLens :: Lens' JVMMemoryInfo Bytes
+jvmMemoryInfoNonHeapInitLens = lens jvmMemoryInfoNonHeapInit (\x y -> x {jvmMemoryInfoNonHeapInit = y})
+
+jvmMemoryInfoHeapMaxLens :: Lens' JVMMemoryInfo Bytes
+jvmMemoryInfoHeapMaxLens = lens jvmMemoryInfoHeapMax (\x y -> x {jvmMemoryInfoHeapMax = y})
+
+jvmMemoryInfoHeapInitLens :: Lens' JVMMemoryInfo Bytes
+jvmMemoryInfoHeapInitLens = lens jvmMemoryInfoHeapInit (\x y -> x {jvmMemoryInfoHeapInit = y})
+
+newtype JVMMemoryPool = JVMMemoryPool
+  { jvmMemoryPool :: Text
+  }
+  deriving newtype (Eq, Show, FromJSON)
+
+newtype JVMGCCollector = JVMGCCollector
+  { jvmGCCollector :: Text
+  }
+  deriving newtype (Eq, Show, FromJSON)
+
+newtype PID = PID
+  { pid :: Int
+  }
+  deriving newtype (Eq, Show, FromJSON)
+
+data NodeOSInfo = NodeOSInfo
+  { nodeOSRefreshInterval :: NominalDiffTime,
+    nodeOSName :: Text,
+    nodeOSArch :: Text,
+    nodeOSVersion :: Text, -- semver breaks on "5.10.60.1-microsoft-standard-WSL2"
+    nodeOSAvailableProcessors :: Int,
+    nodeOSAllocatedProcessors :: Int
+  }
+  deriving stock (Eq, Show)
+
+nodeOSInfoRefreshIntervalLens :: Lens' NodeOSInfo NominalDiffTime
+nodeOSInfoRefreshIntervalLens = lens nodeOSRefreshInterval (\x y -> x {nodeOSRefreshInterval = y})
+
+nodeOSInfoNameLens :: Lens' NodeOSInfo Text
+nodeOSInfoNameLens = lens nodeOSName (\x y -> x {nodeOSName = y})
+
+nodeOSInfoArchLens :: Lens' NodeOSInfo Text
+nodeOSInfoArchLens = lens nodeOSArch (\x y -> x {nodeOSArch = y})
+
+nodeOSInfoVersionLens :: Lens' NodeOSInfo Text
+nodeOSInfoVersionLens = lens nodeOSVersion (\x y -> x {nodeOSVersion = y})
+
+nodeOSInfoAvailableProcessorsLens :: Lens' NodeOSInfo Int
+nodeOSInfoAvailableProcessorsLens = lens nodeOSAvailableProcessors (\x y -> x {nodeOSAvailableProcessors = y})
+
+nodeOSInfoAllocatedProcessorsLens :: Lens' NodeOSInfo Int
+nodeOSInfoAllocatedProcessorsLens = lens nodeOSAllocatedProcessors (\x y -> x {nodeOSAllocatedProcessors = y})
+
+data CPUInfo = CPUInfo
+  { cpuCacheSize :: Bytes,
+    cpuCoresPerSocket :: Int,
+    cpuTotalSockets :: Int,
+    cpuTotalCores :: Int,
+    cpuMHZ :: Int,
+    cpuModel :: Text,
+    cpuVendor :: Text
+  }
+  deriving stock (Eq, Show)
+
+cpuInfoCacheSizeLens :: Lens' CPUInfo Bytes
+cpuInfoCacheSizeLens = lens cpuCacheSize (\x y -> x {cpuCacheSize = y})
+
+cpuInfoCoresPerSocketLens :: Lens' CPUInfo Int
+cpuInfoCoresPerSocketLens = lens cpuCoresPerSocket (\x y -> x {cpuCoresPerSocket = y})
+
+cpuInfoTotalSocketsLens :: Lens' CPUInfo Int
+cpuInfoTotalSocketsLens = lens cpuTotalSockets (\x y -> x {cpuTotalSockets = y})
+
+cpuInfoTotalCoresLens :: Lens' CPUInfo Int
+cpuInfoTotalCoresLens = lens cpuTotalCores (\x y -> x {cpuTotalCores = y})
+
+cpuInfoMHZLens :: Lens' CPUInfo Int
+cpuInfoMHZLens = lens cpuMHZ (\x y -> x {cpuMHZ = y})
+
+cpuInfoModelLens :: Lens' CPUInfo Text
+cpuInfoModelLens = lens cpuModel (\x y -> x {cpuModel = y})
+
+cpuInfoVendorLens :: Lens' CPUInfo Text
+cpuInfoVendorLens = lens cpuVendor (\x y -> x {cpuVendor = y})
+
+data NodeProcessInfo = NodeProcessInfo
+  { -- | See <https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-configuration.html>
+    nodeProcessMLockAll :: Bool,
+    nodeProcessMaxFileDescriptors :: Maybe Int,
+    nodeProcessId :: PID,
+    nodeProcessRefreshInterval :: NominalDiffTime
+  }
+  deriving stock (Eq, Show)
+
+nodeProcessInfoMLockAllLens :: Lens' NodeProcessInfo Bool
+nodeProcessInfoMLockAllLens = lens nodeProcessMLockAll (\x y -> x {nodeProcessMLockAll = y})
+
+nodeProcessInfoMaxFileDescriptorsLens :: Lens' NodeProcessInfo (Maybe Int)
+nodeProcessInfoMaxFileDescriptorsLens = lens nodeProcessMaxFileDescriptors (\x y -> x {nodeProcessMaxFileDescriptors = y})
+
+nodeProcessInfoIdLens :: Lens' NodeProcessInfo PID
+nodeProcessInfoIdLens = lens nodeProcessId (\x y -> x {nodeProcessId = y})
+
+nodeProcessInfoRefreshIntervalLens :: Lens' NodeProcessInfo NominalDiffTime
+nodeProcessInfoRefreshIntervalLens = lens nodeProcessRefreshInterval (\x y -> x {nodeProcessRefreshInterval = y})
+
+instance FromJSON NodesInfo where
+  parseJSON = withObject "NodesInfo" parse
+    where
+      parse o = do
+        nodes <- o .: "nodes"
+        infos <- forM (HM.toList nodes) $ \(fullNID, v) -> do
+          node <- parseJSON v
+          parseNodeInfo (FullNodeId fullNID) node
+        cn <- o .: "cluster_name"
+        return (NodesInfo infos cn)
+
+instance FromJSON NodesStats where
+  parseJSON = withObject "NodesStats" parse
+    where
+      parse o = do
+        nodes <- o .: "nodes"
+        stats <- forM (HM.toList nodes) $ \(fullNID, v) -> do
+          node <- parseJSON v
+          parseNodeStats (FullNodeId fullNID) node
+        cn <- o .: "cluster_name"
+        return (NodesStats stats cn)
+
+instance FromJSON NodeBreakerStats where
+  parseJSON = withObject "NodeBreakerStats" parse
+    where
+      parse o =
+        NodeBreakerStats
+          <$> o
+            .: "tripped"
+          <*> o
+            .: "overhead"
+          <*> o
+            .: "estimated_size_in_bytes"
+          <*> o
+            .: "limit_size_in_bytes"
+
+instance FromJSON NodeHTTPStats where
+  parseJSON = withObject "NodeHTTPStats" parse
+    where
+      parse o =
+        NodeHTTPStats
+          <$> o
+            .: "total_opened"
+          <*> o
+            .: "current_open"
+
+instance FromJSON NodeTransportStats where
+  parseJSON = withObject "NodeTransportStats" parse
+    where
+      parse o =
+        NodeTransportStats
+          <$> o
+            .: "tx_size_in_bytes"
+          <*> o
+            .: "tx_count"
+          <*> o
+            .: "rx_size_in_bytes"
+          <*> o
+            .: "rx_count"
+          <*> o
+            .: "server_open"
+
+instance FromJSON NodeFSStats where
+  parseJSON = withObject "NodeFSStats" parse
+    where
+      parse o =
+        NodeFSStats
+          <$> o
+            .: "data"
+          <*> o
+            .: "total"
+          <*> (posixMS <$> o .: "timestamp")
+
+instance FromJSON NodeDataPathStats where
+  parseJSON = withObject "NodeDataPathStats" parse
+    where
+      parse o =
+        NodeDataPathStats
+          <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
+          <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
+          <*> o
+            .:? "disk_io_size_in_bytes"
+          <*> o
+            .:? "disk_write_size_in_bytes"
+          <*> o
+            .:? "disk_read_size_in_bytes"
+          <*> o
+            .:? "disk_io_op"
+          <*> o
+            .:? "disk_writes"
+          <*> o
+            .:? "disk_reads"
+          <*> o
+            .: "available_in_bytes"
+          <*> o
+            .: "free_in_bytes"
+          <*> o
+            .: "total_in_bytes"
+          <*> o
+            .:? "type"
+          <*> o
+            .:? "dev"
+          <*> o
+            .: "mount"
+          <*> o
+            .: "path"
+
+instance FromJSON NodeFSTotalStats where
+  parseJSON = withObject "NodeFSTotalStats" parse
+    where
+      parse o =
+        NodeFSTotalStats
+          <$> (fmap unStringlyTypedDouble <$> o .:? "disk_service_time")
+          <*> (fmap unStringlyTypedDouble <$> o .:? "disk_queue")
+          <*> o
+            .:? "disk_io_size_in_bytes"
+          <*> o
+            .:? "disk_write_size_in_bytes"
+          <*> o
+            .:? "disk_read_size_in_bytes"
+          <*> o
+            .:? "disk_io_op"
+          <*> o
+            .:? "disk_writes"
+          <*> o
+            .:? "disk_reads"
+          <*> o
+            .: "available_in_bytes"
+          <*> o
+            .: "free_in_bytes"
+          <*> o
+            .: "total_in_bytes"
+
+instance FromJSON NodeNetworkStats where
+  parseJSON = withObject "NodeNetworkStats" parse
+    where
+      parse o = do
+        tcp <- o .: "tcp"
+        NodeNetworkStats
+          <$> tcp
+            .: "out_rsts"
+          <*> tcp
+            .: "in_errs"
+          <*> tcp
+            .: "attempt_fails"
+          <*> tcp
+            .: "estab_resets"
+          <*> tcp
+            .: "retrans_segs"
+          <*> tcp
+            .: "out_segs"
+          <*> tcp
+            .: "in_segs"
+          <*> tcp
+            .: "curr_estab"
+          <*> tcp
+            .: "passive_opens"
+          <*> tcp
+            .: "active_opens"
+
+instance FromJSON NodeThreadPoolStats where
+  parseJSON = withObject "NodeThreadPoolStats" parse
+    where
+      parse o =
+        NodeThreadPoolStats
+          <$> o
+            .: "completed"
+          <*> o
+            .: "largest"
+          <*> o
+            .: "rejected"
+          <*> o
+            .: "active"
+          <*> o
+            .: "queue"
+          <*> o
+            .: "threads"
+
+instance FromJSON NodeJVMStats where
+  parseJSON = withObject "NodeJVMStats" parse
+    where
+      parse o = do
+        bufferPools <- o .: "buffer_pools"
+        mapped <- bufferPools .: "mapped"
+        direct <- bufferPools .: "direct"
+        gc <- o .: "gc"
+        collectors <- gc .: "collectors"
+        oldC <- collectors .: "old"
+        youngC <- collectors .: "young"
+        threads <- o .: "threads"
+        mem <- o .: "mem"
+        pools <- mem .: "pools"
+        oldM <- pools .: "old"
+        survivorM <- pools .: "survivor"
+        youngM <- pools .: "young"
+        NodeJVMStats
+          <$> pure mapped
+          <*> pure direct
+          <*> pure oldC
+          <*> pure youngC
+          <*> threads
+            .: "peak_count"
+          <*> threads
+            .: "count"
+          <*> pure oldM
+          <*> pure survivorM
+          <*> pure youngM
+          <*> mem
+            .: "non_heap_committed_in_bytes"
+          <*> mem
+            .: "non_heap_used_in_bytes"
+          <*> mem
+            .: "heap_max_in_bytes"
+          <*> mem
+            .: "heap_committed_in_bytes"
+          <*> mem
+            .: "heap_used_percent"
+          <*> mem
+            .: "heap_used_in_bytes"
+          <*> (unMS <$> o .: "uptime_in_millis")
+          <*> (posixMS <$> o .: "timestamp")
+
+instance FromJSON JVMBufferPoolStats where
+  parseJSON = withObject "JVMBufferPoolStats" parse
+    where
+      parse o =
+        JVMBufferPoolStats
+          <$> o
+            .: "total_capacity_in_bytes"
+          <*> o
+            .: "used_in_bytes"
+          <*> o
+            .: "count"
+
+instance FromJSON JVMGCStats where
+  parseJSON = withObject "JVMGCStats" parse
+    where
+      parse o =
+        JVMGCStats
+          <$> (unMS <$> o .: "collection_time_in_millis")
+          <*> o
+            .: "collection_count"
+
+instance FromJSON JVMPoolStats where
+  parseJSON = withObject "JVMPoolStats" parse
+    where
+      parse o =
+        JVMPoolStats
+          <$> o
+            .: "peak_max_in_bytes"
+          <*> o
+            .: "peak_used_in_bytes"
+          <*> o
+            .: "max_in_bytes"
+          <*> o
+            .: "used_in_bytes"
+
+instance FromJSON NodeProcessStats where
+  parseJSON = withObject "NodeProcessStats" parse
+    where
+      parse o = do
+        mem <- o .: "mem"
+        cpu <- o .: "cpu"
+        NodeProcessStats
+          <$> (posixMS <$> o .: "timestamp")
+          <*> o
+            .: "open_file_descriptors"
+          <*> o
+            .: "max_file_descriptors"
+          <*> cpu
+            .: "percent"
+          <*> (unMS <$> cpu .: "total_in_millis")
+          <*> mem
+            .: "total_virtual_in_bytes"
+
+instance FromJSON NodeOSStats where
+  parseJSON = withObject "NodeOSStats" parse
+    where
+      parse o = do
+        swap <- o .: "swap"
+        mem <- o .: "mem"
+        cpu <- o .: "cpu"
+        load <- o .:? "load_average"
+        NodeOSStats
+          <$> (posixMS <$> o .: "timestamp")
+          <*> cpu
+            .: "percent"
+          <*> pure load
+          <*> mem
+            .: "total_in_bytes"
+          <*> mem
+            .: "free_in_bytes"
+          <*> mem
+            .: "free_percent"
+          <*> mem
+            .: "used_in_bytes"
+          <*> mem
+            .: "used_percent"
+          <*> swap
+            .: "total_in_bytes"
+          <*> swap
+            .: "free_in_bytes"
+          <*> swap
+            .: "used_in_bytes"
+
+instance FromJSON LoadAvgs where
+  parseJSON = withArray "LoadAvgs" parse
+    where
+      parse v = case V.toList v of
+        [one, five, fifteen] ->
+          LoadAvgs
+            <$> parseJSON one
+            <*> parseJSON five
+            <*> parseJSON fifteen
+        _ -> fail "Expecting a triple of Doubles"
+
+instance FromJSON NodeIndicesStats where
+  parseJSON = withObject "NodeIndicesStats" parse
+    where
+      parse o = do
+        let (.::) mv k = case mv of
+              Just v -> Just <$> v .: k
+              Nothing -> pure Nothing
+        mRecovery <- o .:? "recovery"
+        mQueryCache <- o .:? "query_cache"
+        mSuggest <- o .:? "suggest"
+        translog <- o .: "translog"
+        segments <- o .: "segments"
+        completion <- o .: "completion"
+        mPercolate <- o .:? "percolate"
+        fielddata <- o .: "fielddata"
+        warmer <- o .: "warmer"
+        flush <- o .: "flush"
+        refresh <- o .: "refresh"
+        merges <- o .: "merges"
+        search <- o .: "search"
+        getStats <- o .: "get"
+        indexing <- o .: "indexing"
+        store <- o .: "store"
+        docs <- o .: "docs"
+        NodeIndicesStats
+          <$> (fmap unMS <$> mRecovery .:: "throttle_time_in_millis")
+          <*> mRecovery
+            .:: "current_as_target"
+          <*> mRecovery
+            .:: "current_as_source"
+          <*> mQueryCache
+            .:: "miss_count"
+          <*> mQueryCache
+            .:: "hit_count"
+          <*> mQueryCache
+            .:: "evictions"
+          <*> mQueryCache
+            .:: "memory_size_in_bytes"
+          <*> mSuggest
+            .:: "current"
+          <*> (fmap unMS <$> mSuggest .:: "time_in_millis")
+          <*> mSuggest
+            .:: "total"
+          <*> translog
+            .: "size_in_bytes"
+          <*> translog
+            .: "operations"
+          <*> segments
+            .:? "fixed_bit_set_memory_in_bytes"
+          <*> segments
+            .: "version_map_memory_in_bytes"
+          <*> segments
+            .:? "index_writer_max_memory_in_bytes"
+          <*> segments
+            .: "index_writer_memory_in_bytes"
+          <*> segments
+            .: "memory_in_bytes"
+          <*> segments
+            .: "count"
+          <*> completion
+            .: "size_in_bytes"
+          <*> mPercolate
+            .:: "queries"
+          <*> mPercolate
+            .:: "memory_size_in_bytes"
+          <*> mPercolate
+            .:: "current"
+          <*> (fmap unMS <$> mPercolate .:: "time_in_millis")
+          <*> mPercolate
+            .:: "total"
+          <*> fielddata
+            .: "evictions"
+          <*> fielddata
+            .: "memory_size_in_bytes"
+          <*> (unMS <$> warmer .: "total_time_in_millis")
+          <*> warmer
+            .: "total"
+          <*> warmer
+            .: "current"
+          <*> (unMS <$> flush .: "total_time_in_millis")
+          <*> flush
+            .: "total"
+          <*> (unMS <$> refresh .: "total_time_in_millis")
+          <*> refresh
+            .: "total"
+          <*> merges
+            .: "total_size_in_bytes"
+          <*> merges
+            .: "total_docs"
+          <*> (unMS <$> merges .: "total_time_in_millis")
+          <*> merges
+            .: "total"
+          <*> merges
+            .: "current_size_in_bytes"
+          <*> merges
+            .: "current_docs"
+          <*> merges
+            .: "current"
+          <*> search
+            .: "fetch_current"
+          <*> (unMS <$> search .: "fetch_time_in_millis")
+          <*> search
+            .: "fetch_total"
+          <*> search
+            .: "query_current"
+          <*> (unMS <$> search .: "query_time_in_millis")
+          <*> search
+            .: "query_total"
+          <*> search
+            .: "open_contexts"
+          <*> getStats
+            .: "current"
+          <*> (unMS <$> getStats .: "missing_time_in_millis")
+          <*> getStats
+            .: "missing_total"
+          <*> (unMS <$> getStats .: "exists_time_in_millis")
+          <*> getStats
+            .: "exists_total"
+          <*> (unMS <$> getStats .: "time_in_millis")
+          <*> getStats
+            .: "total"
+          <*> (fmap unMS <$> indexing .:? "throttle_time_in_millis")
+          <*> indexing
+            .:? "is_throttled"
+          <*> indexing
+            .:? "noop_update_total"
+          <*> indexing
+            .: "delete_current"
+          <*> (unMS <$> indexing .: "delete_time_in_millis")
+          <*> indexing
+            .: "delete_total"
+          <*> indexing
+            .: "index_current"
+          <*> (unMS <$> indexing .: "index_time_in_millis")
+          <*> indexing
+            .: "index_total"
+          <*> (fmap unMS <$> store .:? "throttle_time_in_millis")
+          <*> store
+            .: "size_in_bytes"
+          <*> docs
+            .: "deleted"
+          <*> docs
+            .: "count"
+
+instance FromJSON NodeBreakersStats where
+  parseJSON = withObject "NodeBreakersStats" parse
+    where
+      parse o =
+        NodeBreakersStats
+          <$> o
+            .: "parent"
+          <*> o
+            .: "request"
+          <*> o
+            .: "fielddata"
+
+parseNodeStats :: FullNodeId -> Object -> Parser NodeStats
+parseNodeStats fnid o =
+  NodeStats
+    <$> o
+      .: "name"
+    <*> pure fnid
+    <*> o
+      .:? "breakers"
+    <*> o
+      .: "http"
+    <*> o
+      .: "transport"
+    <*> o
+      .: "fs"
+    <*> o
+      .:? "network"
+    <*> o
+      .: "thread_pool"
+    <*> o
+      .: "jvm"
+    <*> o
+      .: "process"
+    <*> o
+      .: "os"
+    <*> o
+      .: "indices"
+
+parseNodeInfo :: FullNodeId -> Object -> Parser NodeInfo
+parseNodeInfo nid o =
+  NodeInfo
+    <$> o
+      .:? "http_address"
+    <*> o
+      .: "build_hash"
+    <*> o
+      .: "version"
+    <*> o
+      .: "ip"
+    <*> o
+      .: "host"
+    <*> o
+      .: "transport_address"
+    <*> o
+      .: "name"
+    <*> pure nid
+    <*> o
+      .: "plugins"
+    <*> o
+      .: "http"
+    <*> o
+      .: "transport"
+    <*> o
+      .:? "network"
+    <*> o
+      .: "thread_pool"
+    <*> o
+      .: "jvm"
+    <*> o
+      .: "process"
+    <*> o
+      .: "os"
+    <*> o
+      .: "settings"
+
+instance FromJSON NodePluginInfo where
+  parseJSON = withObject "NodePluginInfo" parse
+    where
+      parse o =
+        NodePluginInfo
+          <$> o
+            .:? "site"
+          <*> o
+            .:? "jvm"
+          <*> o
+            .: "description"
+          <*> o
+            .: "version"
+          <*> o
+            .: "name"
+
+instance FromJSON NodeHTTPInfo where
+  parseJSON = withObject "NodeHTTPInfo" parse
+    where
+      parse o =
+        NodeHTTPInfo
+          <$> o
+            .: "max_content_length_in_bytes"
+          <*> o
+            .: "publish_address"
+          <*> o
+            .: "bound_address"
+
+instance FromJSON BoundTransportAddress where
+  parseJSON = withObject "BoundTransportAddress" parse
+    where
+      parse o =
+        BoundTransportAddress
+          <$> o
+            .: "publish_address"
+          <*> o
+            .: "bound_address"
+
+instance FromJSON NodeOSInfo where
+  parseJSON = withObject "NodeOSInfo" parse
+    where
+      parse o =
+        NodeOSInfo
+          <$> (unMS <$> o .: "refresh_interval_in_millis")
+          <*> o
+            .: "name"
+          <*> o
+            .: "arch"
+          <*> o
+            .: "version"
+          <*> o
+            .: "available_processors"
+          <*> o
+            .: "allocated_processors"
+
+instance FromJSON CPUInfo where
+  parseJSON = withObject "CPUInfo" parse
+    where
+      parse o =
+        CPUInfo
+          <$> o
+            .: "cache_size_in_bytes"
+          <*> o
+            .: "cores_per_socket"
+          <*> o
+            .: "total_sockets"
+          <*> o
+            .: "total_cores"
+          <*> o
+            .: "mhz"
+          <*> o
+            .: "model"
+          <*> o
+            .: "vendor"
+
+instance FromJSON NodeProcessInfo where
+  parseJSON = withObject "NodeProcessInfo" parse
+    where
+      parse o =
+        NodeProcessInfo
+          <$> o
+            .: "mlockall"
+          <*> o
+            .:? "max_file_descriptors"
+          <*> o
+            .: "id"
+          <*> (unMS <$> o .: "refresh_interval_in_millis")
+
+instance FromJSON NodeJVMInfo where
+  parseJSON = withObject "NodeJVMInfo" parse
+    where
+      parse o =
+        NodeJVMInfo
+          <$> o
+            .: "memory_pools"
+          <*> o
+            .: "gc_collectors"
+          <*> o
+            .: "mem"
+          <*> (posixMS <$> o .: "start_time_in_millis")
+          <*> o
+            .: "vm_vendor"
+          <*> o
+            .: "vm_version"
+          <*> o
+            .: "vm_name"
+          <*> o
+            .: "version"
+          <*> o
+            .: "pid"
+
+instance FromJSON JVMMemoryInfo where
+  parseJSON = withObject "JVMMemoryInfo" parse
+    where
+      parse o =
+        JVMMemoryInfo
+          <$> o
+            .: "direct_max_in_bytes"
+          <*> o
+            .: "non_heap_max_in_bytes"
+          <*> o
+            .: "non_heap_init_in_bytes"
+          <*> o
+            .: "heap_max_in_bytes"
+          <*> o
+            .: "heap_init_in_bytes"
+
+instance FromJSON NodeThreadPoolInfo where
+  parseJSON = withObject "NodeThreadPoolInfo" parse
+    where
+      parse o = do
+        ka <- maybe (return Nothing) (fmap Just . parseStringInterval) =<< o .:? "keep_alive"
+        NodeThreadPoolInfo
+          <$> (parseJSON . unStringlyTypeJSON =<< o .: "queue_size")
+          <*> pure ka
+          <*> o
+            .:? "min"
+          <*> o
+            .:? "max"
+          <*> o
+            .: "type"
+
+instance FromJSON ThreadPoolSize where
+  parseJSON v = parseAsNumber v <|> parseAsString v
+    where
+      parseAsNumber = parseAsInt <=< parseJSON
+      parseAsInt (-1) = return ThreadPoolUnbounded
+      parseAsInt n
+        | n >= 0 = return (ThreadPoolBounded n)
+        | otherwise = fail "Thread pool size must be >= -1."
+      parseAsString = withText "ThreadPoolSize" $ \t ->
+        case first (readMay . T.unpack) (T.span isNumber t) of
+          (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
+          (Just n, "") -> return (ThreadPoolBounded n)
+          _ -> fail ("Invalid thread pool size " <> T.unpack t)
+
+instance FromJSON ThreadPoolType where
+  parseJSON = withText "ThreadPoolType" parse
+    where
+      parse "scaling" = return ThreadPoolScaling
+      parse "fixed" = return ThreadPoolFixed
+      parse "cached" = return ThreadPoolCached
+      parse "fixed_auto_queue_size" = return ThreadPoolFixedAutoQueueSize
+      parse e = fail ("Unexpected thread pool type" <> T.unpack e)
+
+instance FromJSON NodeTransportInfo where
+  parseJSON = withObject "NodeTransportInfo" parse
+    where
+      parse o =
+        NodeTransportInfo
+          <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
+          <*> o
+            .: "publish_address"
+          <*> o
+            .: "bound_address"
+      parseProfiles (Object o) | X.null o = return []
+      parseProfiles v@(Array _) = parseJSON v
+      parseProfiles Null = return []
+      parseProfiles _ = fail "Could not parse profiles"
+
+instance FromJSON NodeNetworkInfo where
+  parseJSON = withObject "NodeNetworkInfo" parse
+    where
+      parse o =
+        NodeNetworkInfo
+          <$> o
+            .: "primary_interface"
+          <*> (unMS <$> o .: "refresh_interval_in_millis")
+
+instance FromJSON NodeNetworkInterface where
+  parseJSON = withObject "NodeNetworkInterface" parse
+    where
+      parse o =
+        NodeNetworkInterface
+          <$> o
+            .: "mac_address"
+          <*> o
+            .: "name"
+          <*> o
+            .: "address"
+
+data InitialShardCount
+  = QuorumShards
+  | QuorumMinus1Shards
+  | FullShards
+  | FullMinus1Shards
+  | ExplicitShards Int
+  deriving stock (Eq, Show, Generic)
+
+initialShardCountExplicitShardsPrism :: Prism' InitialShardCount Int
+initialShardCountExplicitShardsPrism = prism ExplicitShards extract
+  where
+    extract s =
+      case s of
+        ExplicitShards x -> Right x
+        _ -> Left s
+
+instance FromJSON InitialShardCount where
+  parseJSON v =
+    withText "InitialShardCount" parseText v
+      <|> ExplicitShards
+      <$> parseJSON v
+    where
+      parseText "quorum" = pure QuorumShards
+      parseText "quorum-1" = pure QuorumMinus1Shards
+      parseText "full" = pure FullShards
+      parseText "full-1" = pure FullMinus1Shards
+      parseText _ = mzero
+
+instance ToJSON InitialShardCount where
+  toJSON QuorumShards = String "quorum"
+  toJSON QuorumMinus1Shards = String "quorum-1"
+  toJSON FullShards = String "full"
+  toJSON FullMinus1Shards = String "full-1"
+  toJSON (ExplicitShards x) = toJSON x
+
+newtype ShardsResult = ShardsResult
+  { srShards :: ShardResult
+  }
+  deriving stock (Eq, Show)
+
+instance FromJSON ShardsResult where
+  parseJSON =
+    withObject "ShardsResult" $ \v ->
+      ShardsResult
+        <$> v
+          .: "_shards"
+
+shardsResultShardsLens :: Lens' ShardsResult ShardResult
+shardsResultShardsLens = lens srShards (\x y -> x {srShards = y})
+
+data ShardResult = ShardResult
+  { shardTotal :: Int,
+    shardsSuccessful :: Int,
+    shardsSkipped :: Int,
+    shardsFailed :: Int
+  }
+  deriving stock (Eq, Show)
+
+instance FromJSON ShardResult where
+  parseJSON =
+    withObject "ShardResult" $ \v ->
+      ShardResult
+        <$> v .:? "total" .!= 0
+        <*> v .:? "successful" .!= 0
+        <*> v .:? "skipped" .!= 0
+        <*> v .:? "failed" .!= 0
+
+instance ToJSON ShardResult where
+  toJSON ShardResult {..} =
+    object
+      [ "total" .= shardTotal,
+        "successful" .= shardsSuccessful,
+        "skipped" .= shardsSkipped,
+        "failed" .= shardsFailed
+      ]
+
+shardResultTotalLens :: Lens' ShardResult Int
+shardResultTotalLens = lens shardTotal (\x y -> x {shardTotal = y})
+
+shardsResultSuccessfulLens :: Lens' ShardResult Int
+shardsResultSuccessfulLens = lens shardsSuccessful (\x y -> x {shardsSuccessful = y})
+
+shardsResultResultSkippedLens :: Lens' ShardResult Int
+shardsResultResultSkippedLens = lens shardsSkipped (\x y -> x {shardsSkipped = y})
+
+shardsResultFailedLens :: Lens' ShardResult Int
+shardsResultFailedLens = lens shardsFailed (\x y -> x {shardsFailed = y})
+
+-- | 'Version' is embedded in 'Status'
+data Version = Version
+  { number :: VersionNumber,
+    build_hash :: BuildHash,
+    build_date :: UTCTime,
+    build_snapshot :: Bool,
+    lucene_version :: VersionNumber
+  }
+  deriving stock (Eq, Show, Generic)
+
+instance ToJSON Version where
+  toJSON Version {..} =
+    object
+      [ "number" .= number,
+        "build_hash" .= build_hash,
+        "build_date" .= build_date,
+        "build_snapshot" .= build_snapshot,
+        "lucene_version" .= lucene_version
+      ]
+
+instance FromJSON Version where
+  parseJSON = withObject "Version" parse
+    where
+      parse o =
+        Version
+          <$> o
+            .: "number"
+          <*> o
+            .: "build_hash"
+          <*> o
+            .: "build_date"
+          <*> o
+            .: "build_snapshot"
+          <*> o
+            .: "lucene_version"
+
+versionNumberLens :: Lens' Version VersionNumber
+versionNumberLens = lens number (\x y -> x {number = y})
+
+versionBuildHashLens :: Lens' Version BuildHash
+versionBuildHashLens = lens build_hash (\x y -> x {build_hash = y})
+
+versionBuildDateLens :: Lens' Version UTCTime
+versionBuildDateLens = lens build_date (\x y -> x {build_date = y})
+
+versionBuildSnapshotLens :: Lens' Version Bool
+versionBuildSnapshotLens = lens build_snapshot (\x y -> x {build_snapshot = y})
+
+versionLuceneVersionLens :: Lens' Version VersionNumber
+versionLuceneVersionLens = lens lucene_version (\x y -> x {lucene_version = y})
+
+-- | Traditional software versioning number
+newtype VersionNumber = VersionNumber
+  {versionNumber :: Versions.Version}
+  deriving stock (Eq, Ord, Show)
+
+instance ToJSON VersionNumber where
+  toJSON = toJSON . Versions.prettyVer . versionNumber
+
+instance FromJSON VersionNumber where
+  parseJSON = withText "VersionNumber" parse
+    where
+      parse t =
+        case Versions.version t of
+          (Left err) -> fail $ show err
+          (Right v) -> return (VersionNumber v)
+
+data HealthStatus = HealthStatus
+  { healthStatusClusterName :: Text,
+    healthStatusStatus :: Text,
+    healthStatusTimedOut :: Bool,
+    healthStatusNumberOfNodes :: Int,
+    healthStatusNumberOfDataNodes :: Int,
+    healthStatusActivePrimaryShards :: Int,
+    healthStatusActiveShards :: Int,
+    healthStatusRelocatingShards :: Int,
+    healthStatusInitializingShards :: Int,
+    healthStatusUnassignedShards :: Int,
+    healthStatusDelayedUnassignedShards :: Int,
+    healthStatusNumberOfPendingTasks :: Int,
+    healthStatusNumberOfInFlightFetch :: Int,
+    healthStatusTaskMaxWaitingInQueueMillis :: Int,
+    healthStatusActiveShardsPercentAsNumber :: Float
+  }
+  deriving stock (Eq, Show)
+
+instance FromJSON HealthStatus where
+  parseJSON =
+    withObject "HealthStatus" $ \v ->
+      HealthStatus
+        <$> v
+          .: "cluster_name"
+        <*> v
+          .: "status"
+        <*> v
+          .: "timed_out"
+        <*> v
+          .: "number_of_nodes"
+        <*> v
+          .: "number_of_data_nodes"
+        <*> v
+          .: "active_primary_shards"
+        <*> v
+          .: "active_shards"
+        <*> v
+          .: "relocating_shards"
+        <*> v
+          .: "initializing_shards"
+        <*> v
+          .: "unassigned_shards"
+        <*> v
+          .: "delayed_unassigned_shards"
+        <*> v
+          .: "number_of_pending_tasks"
+        <*> v
+          .: "number_of_in_flight_fetch"
+        <*> v
+          .: "task_max_waiting_in_queue_millis"
+        <*> v
+          .: "active_shards_percent_as_number"
+
+healthStatusClusterNameLens :: Lens' HealthStatus Text
+healthStatusClusterNameLens = lens healthStatusClusterName (\x y -> x {healthStatusClusterName = y})
+
+healthStatusStatusLens :: Lens' HealthStatus Text
+healthStatusStatusLens = lens healthStatusStatus (\x y -> x {healthStatusStatus = y})
+
+healthStatusTimedOutLens :: Lens' HealthStatus Bool
+healthStatusTimedOutLens = lens healthStatusTimedOut (\x y -> x {healthStatusTimedOut = y})
+
+healthStatusNumberOfNodesLens :: Lens' HealthStatus Int
+healthStatusNumberOfNodesLens = lens healthStatusNumberOfNodes (\x y -> x {healthStatusNumberOfNodes = y})
+
+healthStatusNumberOfDataNodesLens :: Lens' HealthStatus Int
+healthStatusNumberOfDataNodesLens = lens healthStatusNumberOfDataNodes (\x y -> x {healthStatusNumberOfDataNodes = y})
+
+healthStatusActivePrimaryShardsLens :: Lens' HealthStatus Int
+healthStatusActivePrimaryShardsLens = lens healthStatusActivePrimaryShards (\x y -> x {healthStatusActivePrimaryShards = y})
+
+healthStatusActiveShardsLens :: Lens' HealthStatus Int
+healthStatusActiveShardsLens = lens healthStatusActiveShards (\x y -> x {healthStatusActiveShards = y})
+
+healthStatusRelocatingShardsLens :: Lens' HealthStatus Int
+healthStatusRelocatingShardsLens = lens healthStatusRelocatingShards (\x y -> x {healthStatusRelocatingShards = y})
+
+healthStatusInitializingShardsLens :: Lens' HealthStatus Int
+healthStatusInitializingShardsLens = lens healthStatusInitializingShards (\x y -> x {healthStatusInitializingShards = y})
+
+healthStatusUnassignedShardsLens :: Lens' HealthStatus Int
+healthStatusUnassignedShardsLens = lens healthStatusUnassignedShards (\x y -> x {healthStatusUnassignedShards = y})
+
+healthStatusDelayedUnassignedShardsLens :: Lens' HealthStatus Int
+healthStatusDelayedUnassignedShardsLens = lens healthStatusDelayedUnassignedShards (\x y -> x {healthStatusDelayedUnassignedShards = y})
+
+healthStatusNumberOfPendingTasksLens :: Lens' HealthStatus Int
+healthStatusNumberOfPendingTasksLens = lens healthStatusNumberOfPendingTasks (\x y -> x {healthStatusNumberOfPendingTasks = y})
+
+healthStatusNumberOfInFlightFetchLens :: Lens' HealthStatus Int
+healthStatusNumberOfInFlightFetchLens = lens healthStatusNumberOfInFlightFetch (\x y -> x {healthStatusNumberOfInFlightFetch = y})
+
+healthStatusTaskMaxWaitingInQueueMillisLens :: Lens' HealthStatus Int
+healthStatusTaskMaxWaitingInQueueMillisLens = lens healthStatusTaskMaxWaitingInQueueMillis (\x y -> x {healthStatusTaskMaxWaitingInQueueMillis = y})
+
+healthStatusActiveShardsPercentAsNumberLens :: Lens' HealthStatus Float
+healthStatusActiveShardsPercentAsNumberLens = lens healthStatusActiveShardsPercentAsNumber (\x y -> x {healthStatusActiveShardsPercentAsNumber = y})
+
+data IndexedDocument = IndexedDocument
+  { idxDocIndex :: Text,
+    idxDocType :: Maybe Text,
+    idxDocId :: Text,
+    idxDocVersion :: Int,
+    idxDocResult :: Text,
+    idxDocShards :: ShardResult,
+    idxDocSeqNo :: Int,
+    idxDocPrimaryTerm :: Int
+  }
+  deriving stock (Eq, Show)
+
+{-# DEPRECATED idxDocType "deprecated since ElasticSearch 6.0" #-}
+
+instance FromJSON IndexedDocument where
+  parseJSON =
+    withObject "IndexedDocument" $ \v ->
+      IndexedDocument
+        <$> v
+          .: "_index"
+        <*> v
+          .:? "_type"
+        <*> v
+          .: "_id"
+        <*> v
+          .: "_version"
+        <*> v
+          .: "result"
+        <*> v
+          .: "_shards"
+        <*> v
+          .: "_seq_no"
+        <*> v
+          .: "_primary_term"
+
+indexedDocumentIndexLens :: Lens' IndexedDocument Text
+indexedDocumentIndexLens = lens idxDocIndex (\x y -> x {idxDocIndex = y})
+
+indexedDocumentTypeLens :: Lens' IndexedDocument (Maybe Text)
+indexedDocumentTypeLens = lens idxDocType (\x y -> x {idxDocType = y})
+
+indexedDocumentIdLens :: Lens' IndexedDocument Text
+indexedDocumentIdLens = lens idxDocId (\x y -> x {idxDocId = y})
+
+indexedDocumentVersionLens :: Lens' IndexedDocument Int
+indexedDocumentVersionLens = lens idxDocVersion (\x y -> x {idxDocVersion = y})
+
+indexedDocumentResultLens :: Lens' IndexedDocument Text
+indexedDocumentResultLens = lens idxDocResult (\x y -> x {idxDocResult = y})
+
+indexedDocumentShardsLens :: Lens' IndexedDocument ShardResult
+indexedDocumentShardsLens = lens idxDocShards (\x y -> x {idxDocShards = y})
+
+indexedDocumentSeqNoLens :: Lens' IndexedDocument Int
+indexedDocumentSeqNoLens = lens idxDocSeqNo (\x y -> x {idxDocSeqNo = y})
+
+indexedDocumentPrimaryTermLens :: Lens' IndexedDocument Int
+indexedDocumentPrimaryTermLens = lens idxDocPrimaryTerm (\x y -> x {idxDocPrimaryTerm = y})
+
+data DeletedDocuments = DeletedDocuments
+  { delDocsTook :: Int,
+    delDocsTimedOut :: Bool,
+    delDocsTotal :: Int,
+    delDocsDeleted :: Int,
+    delDocsBatches :: Int,
+    delDocsVersionConflicts :: Int,
+    delDocsNoops :: Int,
+    delDocsRetries :: DeletedDocumentsRetries,
+    delDocsThrottledMillis :: Int,
+    delDocsRequestsPerSecond :: Float,
+    delDocsThrottledUntilMillis :: Int,
+    delDocsFailures :: [Value] -- TODO find examples
+  }
+  deriving stock (Eq, Show)
+
+instance FromJSON DeletedDocuments where
+  parseJSON =
+    withObject "DeletedDocuments" $ \v ->
+      DeletedDocuments
+        <$> v
+          .: "took"
+        <*> v
+          .: "timed_out"
+        <*> v
+          .: "total"
+        <*> v
+          .: "deleted"
+        <*> v
+          .: "batches"
+        <*> v
+          .: "version_conflicts"
+        <*> v
+          .: "noops"
+        <*> v
+          .: "retries"
+        <*> v
+          .: "throttled_millis"
+        <*> v
+          .: "requests_per_second"
+        <*> v
+          .: "throttled_until_millis"
+        <*> v
+          .: "failures"
+
+deletedDocumentsTookLens :: Lens' DeletedDocuments Int
+deletedDocumentsTookLens = lens delDocsTook (\x y -> x {delDocsTook = y})
+
+deletedDocumentsTimedOutLens :: Lens' DeletedDocuments Bool
+deletedDocumentsTimedOutLens = lens delDocsTimedOut (\x y -> x {delDocsTimedOut = y})
+
+deletedDocumentsTotalLens :: Lens' DeletedDocuments Int
+deletedDocumentsTotalLens = lens delDocsTotal (\x y -> x {delDocsTotal = y})
+
+deletedDocumentsDeletedLens :: Lens' DeletedDocuments Int
+deletedDocumentsDeletedLens = lens delDocsDeleted (\x y -> x {delDocsDeleted = y})
+
+deletedDocumentsBatchesLens :: Lens' DeletedDocuments Int
+deletedDocumentsBatchesLens = lens delDocsBatches (\x y -> x {delDocsBatches = y})
+
+deletedDocumentsVersionConflictsLens :: Lens' DeletedDocuments Int
+deletedDocumentsVersionConflictsLens = lens delDocsVersionConflicts (\x y -> x {delDocsVersionConflicts = y})
+
+deletedDocumentsNoopsLens :: Lens' DeletedDocuments Int
+deletedDocumentsNoopsLens = lens delDocsNoops (\x y -> x {delDocsNoops = y})
+
+deletedDocumentsRetriesLens :: Lens' DeletedDocuments DeletedDocumentsRetries
+deletedDocumentsRetriesLens = lens delDocsRetries (\x y -> x {delDocsRetries = y})
+
+deletedDocumentsThrottledMillisLens :: Lens' DeletedDocuments Int
+deletedDocumentsThrottledMillisLens = lens delDocsThrottledMillis (\x y -> x {delDocsThrottledMillis = y})
+
+deletedDocumentsRequestsPerSecondLens :: Lens' DeletedDocuments Float
+deletedDocumentsRequestsPerSecondLens = lens delDocsRequestsPerSecond (\x y -> x {delDocsRequestsPerSecond = y})
+
+deletedDocumentsThrottledUntilMillisLens :: Lens' DeletedDocuments Int
+deletedDocumentsThrottledUntilMillisLens = lens delDocsThrottledUntilMillis (\x y -> x {delDocsThrottledUntilMillis = y})
+
+deletedDocumentsFailuresLens :: Lens' DeletedDocuments [Value]
+deletedDocumentsFailuresLens = lens delDocsFailures (\x y -> x {delDocsFailures = y})
+
+data DeletedDocumentsRetries = DeletedDocumentsRetries
+  { delDocsRetriesBulk :: Int,
+    delDocsRetriesSearch :: Int
+  }
+  deriving stock (Eq, Show)
+
+instance FromJSON DeletedDocumentsRetries where
+  parseJSON =
+    withObject "DeletedDocumentsRetries" $ \v ->
+      DeletedDocumentsRetries
+        <$> v
+          .: "bulk"
+        <*> v
+          .: "search"
+
+deletedDocumentsRetriesBulkLens :: Lens' DeletedDocumentsRetries Int
+deletedDocumentsRetriesBulkLens = lens delDocsRetriesBulk (\x y -> x {delDocsRetriesBulk = y})
+
+deletedDocumentsRetriesSearchLens :: Lens' DeletedDocumentsRetries Int
+deletedDocumentsRetriesSearchLens = lens delDocsRetriesSearch (\x y -> x {delDocsRetriesSearch = y})
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query.hs
@@ -36,6 +36,69 @@
     functionScoreFunctionsPair,
     mkBoolQuery,
     showDistanceUnit,
+
+    -- * Optics
+    nestedQueryPathLens,
+    nestedQueryScoreTypeLens,
+    nestedQueryLens,
+    nestedQueryInnerHitsLens,
+    indicesQueryIndicesLens,
+    indicesQueryLens,
+    indicesQueryNoMatchLens,
+    hasParentQueryTypeLens,
+    hasParentQueryLens,
+    hasParentQueryScoreLens,
+    hasParentIgnoreUnmappedLens,
+    hasChildQueryTypeLens,
+    hasChildQueryLens,
+    hasChildQueryScoreTypeLens,
+    hasChildIgnoreUnmapppedLens,
+    hasChildMinChildrenLens,
+    hasChildMaxChildrenLens,
+    disMaxQueriesLens,
+    disMaxTiebreakerLens,
+    disMaxBoostLens,
+    boolQueryMustMatchLens,
+    boolQueryFilterLens,
+    boolQueryMustNotMatchLens,
+    boolQueryShouldMatchLens,
+    boolQueryMinimumShouldMatchLens,
+    boolQueryBoostLens,
+    boolQueryDisableCoordLens,
+    boostingQueryPositiveQueryLens,
+    boostingQueryNegativeQueryLens,
+    boostingQueryNegativeBoostLens,
+    termFieldLens,
+    termValueLens,
+    boolMatchMustMatchPrism,
+    boolMatchMustNotMatchPrism,
+    boolMatchShouldMatchPrism,
+    latLonLatLens,
+    latLonLonLens,
+    geoBoundingBoxTopLeftLens,
+    geoBoundingBoxBottomRightLens,
+    geoBoundingBoxConstraintGeoBBFieldLens,
+    geoBoundingBoxConstraintConstraintBoxLens,
+    geoBoundingBoxConstraintBbConstraintcacheLens,
+    geoBoundingBoxConstraintGeoTypeLens,
+    geoPointGeoFieldLens,
+    geoPointLatLonLens,
+    distanceCoefficientLens,
+    distanceUnitLens,
+    distanceRangeDistanceFromLens,
+    distanceRangeDistanceToLens,
+    functionScoreQueryLens,
+    functionScoreBoostLens,
+    functionScoreFunctionsLens,
+    functionScoreMaxBoostLens,
+    functionScoreBoostModeLens,
+    functionScoreMinScoreLens,
+    functionScoreScoreModeLens,
+    componentScoreFunctionFilterLens,
+    componentScoreFunctionLens,
+    componentScoreFunctionWeightLens,
+    innerHitsFromLens,
+    innerHitsSizeLens,
   )
 where
 
@@ -179,56 +242,56 @@
         termQuery
           `taggedWith` "term"
           <|> termsQuery
-            `taggedWith` "terms"
+          `taggedWith` "terms"
           <|> idsQuery
-            `taggedWith` "ids"
+          `taggedWith` "ids"
           <|> queryQueryStringQuery
-            `taggedWith` "query_string"
+          `taggedWith` "query_string"
           <|> queryMatchQuery
-            `taggedWith` "match"
+          `taggedWith` "match"
           <|> queryMultiMatchQuery
           <|> queryBoolQuery
-            `taggedWith` "bool"
+          `taggedWith` "bool"
           <|> queryBoostingQuery
-            `taggedWith` "boosting"
+          `taggedWith` "boosting"
           <|> queryCommonTermsQuery
-            `taggedWith` "common"
+          `taggedWith` "common"
           <|> constantScoreQuery
-            `taggedWith` "constant_score"
+          `taggedWith` "constant_score"
           <|> queryFunctionScoreQuery
-            `taggedWith` "function_score"
+          `taggedWith` "function_score"
           <|> queryDisMaxQuery
-            `taggedWith` "dis_max"
+          `taggedWith` "dis_max"
           <|> queryFuzzyLikeThisQuery
-            `taggedWith` "fuzzy_like_this"
+          `taggedWith` "fuzzy_like_this"
           <|> queryFuzzyLikeFieldQuery
-            `taggedWith` "fuzzy_like_this_field"
+          `taggedWith` "fuzzy_like_this_field"
           <|> queryFuzzyQuery
-            `taggedWith` "fuzzy"
+          `taggedWith` "fuzzy"
           <|> queryHasChildQuery
-            `taggedWith` "has_child"
+          `taggedWith` "has_child"
           <|> queryHasParentQuery
-            `taggedWith` "has_parent"
+          `taggedWith` "has_parent"
           <|> queryIndicesQuery
-            `taggedWith` "indices"
+          `taggedWith` "indices"
           <|> matchAllQuery
-            `taggedWith` "match_all"
+          `taggedWith` "match_all"
           <|> queryMoreLikeThisQuery
-            `taggedWith` "more_like_this"
+          `taggedWith` "more_like_this"
           <|> queryMoreLikeThisFieldQuery
-            `taggedWith` "more_like_this_field"
+          `taggedWith` "more_like_this_field"
           <|> queryNestedQuery
-            `taggedWith` "nested"
+          `taggedWith` "nested"
           <|> queryPrefixQuery
-            `taggedWith` "prefix"
+          `taggedWith` "prefix"
           <|> queryRangeQuery
-            `taggedWith` "range"
+          `taggedWith` "range"
           <|> queryRegexpQuery
-            `taggedWith` "regexp"
+          `taggedWith` "regexp"
           <|> querySimpleQueryStringQuery
-            `taggedWith` "simple_query_string"
+          `taggedWith` "simple_query_string"
           <|> queryWildcardQuery
-            `taggedWith` "wildcard"
+          `taggedWith` "wildcard"
         where
           taggedWith parser k = parser =<< o .: k
       termQuery = fieldTagged $ \(FieldName fn) o ->
@@ -291,6 +354,18 @@
   }
   deriving stock (Eq, Show, Generic)
 
+nestedQueryPathLens :: Lens' NestedQuery QueryPath
+nestedQueryPathLens = lens nestedQueryPath (\x y -> x {nestedQueryPath = y})
+
+nestedQueryScoreTypeLens :: Lens' NestedQuery ScoreType
+nestedQueryScoreTypeLens = lens nestedQueryScoreType (\x y -> x {nestedQueryScoreType = y})
+
+nestedQueryLens :: Lens' NestedQuery Query
+nestedQueryLens = lens nestedQuery (\x y -> x {nestedQuery = y})
+
+nestedQueryInnerHitsLens :: Lens' NestedQuery (Maybe InnerHits)
+nestedQueryInnerHitsLens = lens nestedQueryInnerHits (\x y -> x {nestedQueryInnerHits = y})
+
 instance ToJSON NestedQuery where
   toJSON (NestedQuery nqPath nqScoreType nqQuery nqInnerHits) =
     omitNulls
@@ -318,6 +393,15 @@
   }
   deriving stock (Eq, Show, Generic)
 
+indicesQueryIndicesLens :: Lens' IndicesQuery [IndexName]
+indicesQueryIndicesLens = lens indicesQueryIndices (\x y -> x {indicesQueryIndices = y})
+
+indicesQueryLens :: Lens' IndicesQuery Query
+indicesQueryLens = lens indicesQuery (\x y -> x {indicesQuery = y})
+
+indicesQueryNoMatchLens :: Lens' IndicesQuery (Maybe Query)
+indicesQueryNoMatchLens = lens indicesQueryNoMatch (\x y -> x {indicesQueryNoMatch = y})
+
 instance ToJSON IndicesQuery where
   toJSON (IndicesQuery indices query noMatch) =
     omitNulls
@@ -343,6 +427,18 @@
   }
   deriving stock (Eq, Show, Generic)
 
+hasParentQueryTypeLens :: Lens' HasParentQuery RelationName
+hasParentQueryTypeLens = lens hasParentQueryType (\x y -> x {hasParentQueryType = y})
+
+hasParentQueryLens :: Lens' HasParentQuery Query
+hasParentQueryLens = lens hasParentQuery (\x y -> x {hasParentQuery = y})
+
+hasParentQueryScoreLens :: Lens' HasParentQuery (Maybe AggregateParentScore)
+hasParentQueryScoreLens = lens hasParentQueryScore (\x y -> x {hasParentQueryScore = y})
+
+hasParentIgnoreUnmappedLens :: Lens' HasParentQuery (Maybe IgnoreUnmapped)
+hasParentIgnoreUnmappedLens = lens hasParentIgnoreUnmapped (\x y -> x {hasParentIgnoreUnmapped = y})
+
 instance ToJSON HasParentQuery where
   toJSON (HasParentQuery queryType query scoreType ignoreUnmapped) =
     omitNulls
@@ -372,6 +468,24 @@
   }
   deriving stock (Eq, Show, Generic)
 
+hasChildQueryTypeLens :: Lens' HasChildQuery RelationName
+hasChildQueryTypeLens = lens hasChildQueryType (\x y -> x {hasChildQueryType = y})
+
+hasChildQueryLens :: Lens' HasChildQuery Query
+hasChildQueryLens = lens hasChildQuery (\x y -> x {hasChildQuery = y})
+
+hasChildQueryScoreTypeLens :: Lens' HasChildQuery (Maybe ScoreType)
+hasChildQueryScoreTypeLens = lens hasChildQueryScoreType (\x y -> x {hasChildQueryScoreType = y})
+
+hasChildIgnoreUnmapppedLens :: Lens' HasChildQuery (Maybe IgnoreUnmapped)
+hasChildIgnoreUnmapppedLens = lens hasChildIgnoreUnmappped (\x y -> x {hasChildIgnoreUnmappped = y})
+
+hasChildMinChildrenLens :: Lens' HasChildQuery (Maybe MinChildren)
+hasChildMinChildrenLens = lens hasChildMinChildren (\x y -> x {hasChildMinChildren = y})
+
+hasChildMaxChildrenLens :: Lens' HasChildQuery (Maybe MaxChildren)
+hasChildMaxChildrenLens = lens hasChildMaxChildren (\x y -> x {hasChildMaxChildren = y})
+
 instance ToJSON HasChildQuery where
   toJSON (HasChildQuery queryType query scoreType ignoreUnmapped minChildren maxChildren) =
     omitNulls
@@ -425,6 +539,15 @@
   }
   deriving stock (Eq, Show, Generic)
 
+disMaxQueriesLens :: Lens' DisMaxQuery [Query]
+disMaxQueriesLens = lens disMaxQueries (\x y -> x {disMaxQueries = y})
+
+disMaxTiebreakerLens :: Lens' DisMaxQuery Tiebreaker
+disMaxTiebreakerLens = lens disMaxTiebreaker (\x y -> x {disMaxTiebreaker = y})
+
+disMaxBoostLens :: Lens' DisMaxQuery (Maybe Boost)
+disMaxBoostLens = lens disMaxBoost (\x y -> x {disMaxBoost = y})
+
 instance ToJSON DisMaxQuery where
   toJSON (DisMaxQuery queries tiebreaker boost) =
     omitNulls base
@@ -455,6 +578,27 @@
   }
   deriving stock (Eq, Show, Generic)
 
+boolQueryMustMatchLens :: Lens' BoolQuery [Query]
+boolQueryMustMatchLens = lens boolQueryMustMatch (\x y -> x {boolQueryMustMatch = y})
+
+boolQueryFilterLens :: Lens' BoolQuery [Filter]
+boolQueryFilterLens = lens boolQueryFilter (\x y -> x {boolQueryFilter = y})
+
+boolQueryMustNotMatchLens :: Lens' BoolQuery [Query]
+boolQueryMustNotMatchLens = lens boolQueryMustNotMatch (\x y -> x {boolQueryMustNotMatch = y})
+
+boolQueryShouldMatchLens :: Lens' BoolQuery [Query]
+boolQueryShouldMatchLens = lens boolQueryShouldMatch (\x y -> x {boolQueryShouldMatch = y})
+
+boolQueryMinimumShouldMatchLens :: Lens' BoolQuery (Maybe MinimumMatch)
+boolQueryMinimumShouldMatchLens = lens boolQueryMinimumShouldMatch (\x y -> x {boolQueryMinimumShouldMatch = y})
+
+boolQueryBoostLens :: Lens' BoolQuery (Maybe Boost)
+boolQueryBoostLens = lens boolQueryBoost (\x y -> x {boolQueryBoost = y})
+
+boolQueryDisableCoordLens :: Lens' BoolQuery (Maybe DisableCoord)
+boolQueryDisableCoordLens = lens boolQueryDisableCoord (\x y -> x {boolQueryDisableCoord = y})
+
 instance ToJSON BoolQuery where
   toJSON (BoolQuery mustM filterM' notM shouldM bqMin boost disableCoord) =
     omitNulls base
@@ -493,6 +637,15 @@
   }
   deriving stock (Eq, Show, Generic)
 
+boostingQueryPositiveQueryLens :: Lens' BoostingQuery Query
+boostingQueryPositiveQueryLens = lens positiveQuery (\x y -> x {positiveQuery = y})
+
+boostingQueryNegativeQueryLens :: Lens' BoostingQuery Query
+boostingQueryNegativeQueryLens = lens negativeQuery (\x y -> x {negativeQuery = y})
+
+boostingQueryNegativeBoostLens :: Lens' BoostingQuery Boost
+boostingQueryNegativeBoostLens = lens negativeBoost (\x y -> x {negativeBoost = y})
+
 instance ToJSON BoostingQuery where
   toJSON (BoostingQuery bqPositiveQuery bqNegativeQuery bqNegativeBoost) =
     object
@@ -533,6 +686,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+termFieldLens :: Lens' Term Key
+termFieldLens = lens termField (\x y -> x {termField = y})
+
+termValueLens :: Lens' Term Text
+termValueLens = lens termValue (\x y -> x {termValue = y})
+
 instance ToJSON Term where
   toJSON (Term field value) =
     object
@@ -556,6 +715,30 @@
   | ShouldMatch [Term] Cache
   deriving stock (Eq, Show, Generic)
 
+boolMatchMustMatchPrism :: Prism' BoolMatch (Term, Cache)
+boolMatchMustMatchPrism = prism (uncurry MustMatch) extract
+  where
+    extract bm =
+      case bm of
+        MustMatch t c -> Right (t, c)
+        _ -> Left bm
+
+boolMatchMustNotMatchPrism :: Prism' BoolMatch (Term, Cache)
+boolMatchMustNotMatchPrism = prism (uncurry MustNotMatch) extract
+  where
+    extract bm =
+      case bm of
+        MustNotMatch t c -> Right (t, c)
+        _ -> Left bm
+
+boolMatchShouldMatchPrism :: Prism' BoolMatch ([Term], Cache)
+boolMatchShouldMatchPrism = prism (uncurry ShouldMatch) extract
+  where
+    extract bm =
+      case bm of
+        ShouldMatch t c -> Right (t, c)
+        _ -> Left bm
+
 instance ToJSON BoolMatch where
   toJSON (MustMatch term cache) =
     object
@@ -580,9 +763,9 @@
         mustMatch
           `taggedWith` "must"
           <|> mustNotMatch
-            `taggedWith` "must_not"
+          `taggedWith` "must_not"
           <|> shouldMatch
-            `taggedWith` "should"
+          `taggedWith` "should"
         where
           taggedWith parser k = parser =<< o .: k
           mustMatch t = MustMatch t <$> o .:? "_cache" .!= defaultCache
@@ -612,6 +795,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+latLonLatLens :: Lens' LatLon Double
+latLonLatLens = lens lat (\x y -> x {lat = y})
+
+latLonLonLens :: Lens' LatLon Double
+latLonLonLens = lens lon (\x y -> x {lon = y})
+
 instance ToJSON LatLon where
   toJSON (LatLon lLat lLon) =
     object
@@ -633,6 +822,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+geoBoundingBoxTopLeftLens :: Lens' GeoBoundingBox LatLon
+geoBoundingBoxTopLeftLens = lens topLeft (\x y -> x {topLeft = y})
+
+geoBoundingBoxBottomRightLens :: Lens' GeoBoundingBox LatLon
+geoBoundingBoxBottomRightLens = lens bottomRight (\x y -> x {bottomRight = y})
+
 instance ToJSON GeoBoundingBox where
   toJSON (GeoBoundingBox gbbTopLeft gbbBottomRight) =
     object
@@ -656,6 +851,18 @@
   }
   deriving stock (Eq, Show, Generic)
 
+geoBoundingBoxConstraintGeoBBFieldLens :: Lens' GeoBoundingBoxConstraint FieldName
+geoBoundingBoxConstraintGeoBBFieldLens = lens geoBBField (\x y -> x {geoBBField = y})
+
+geoBoundingBoxConstraintConstraintBoxLens :: Lens' GeoBoundingBoxConstraint GeoBoundingBox
+geoBoundingBoxConstraintConstraintBoxLens = lens constraintBox (\x y -> x {constraintBox = y})
+
+geoBoundingBoxConstraintBbConstraintcacheLens :: Lens' GeoBoundingBoxConstraint Cache
+geoBoundingBoxConstraintBbConstraintcacheLens = lens bbConstraintcache (\x y -> x {bbConstraintcache = y})
+
+geoBoundingBoxConstraintGeoTypeLens :: Lens' GeoBoundingBoxConstraint GeoFilterType
+geoBoundingBoxConstraintGeoTypeLens = lens geoType (\x y -> x {geoType = y})
+
 instance ToJSON GeoBoundingBoxConstraint where
   toJSON
     ( GeoBoundingBoxConstraint
@@ -687,6 +894,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+geoPointGeoFieldLens :: Lens' GeoPoint FieldName
+geoPointGeoFieldLens = lens geoField (\x y -> x {geoField = y})
+
+geoPointLatLonLens :: Lens' GeoPoint LatLon
+geoPointLatLonLens = lens latLon (\x y -> x {latLon = y})
+
 instance ToJSON GeoPoint where
   toJSON (GeoPoint (FieldName geoPointField) geoPointLatLon) =
     object [fromText geoPointField .= geoPointLatLon]
@@ -776,6 +989,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+distanceCoefficientLens :: Lens' Distance Double
+distanceCoefficientLens = lens coefficient (\x y -> x {coefficient = y})
+
+distanceUnitLens :: Lens' Distance DistanceUnit
+distanceUnitLens = lens unit (\x y -> x {unit = y})
+
 instance ToJSON Distance where
   toJSON (Distance dCoefficient dUnit) =
     String boltedTogether
@@ -806,6 +1025,12 @@
   }
   deriving stock (Eq, Show, Generic)
 
+distanceRangeDistanceFromLens :: Lens' DistanceRange Distance
+distanceRangeDistanceFromLens = lens distanceFrom (\x y -> x {distanceFrom = y})
+
+distanceRangeDistanceToLens :: Lens' DistanceRange Distance
+distanceRangeDistanceToLens = lens distanceTo (\x y -> x {distanceTo = y})
+
 type TemplateQueryValue = Text
 
 newtype TemplateQueryKeyValuePairs
@@ -842,6 +1067,27 @@
   }
   deriving stock (Eq, Show, Generic)
 
+functionScoreQueryLens :: Lens' FunctionScoreQuery (Maybe Query)
+functionScoreQueryLens = lens functionScoreQuery (\x y -> x {functionScoreQuery = y})
+
+functionScoreBoostLens :: Lens' FunctionScoreQuery (Maybe Boost)
+functionScoreBoostLens = lens functionScoreBoost (\x y -> x {functionScoreBoost = y})
+
+functionScoreFunctionsLens :: Lens' FunctionScoreQuery FunctionScoreFunctions
+functionScoreFunctionsLens = lens functionScoreFunctions (\x y -> x {functionScoreFunctions = y})
+
+functionScoreMaxBoostLens :: Lens' FunctionScoreQuery (Maybe Boost)
+functionScoreMaxBoostLens = lens functionScoreMaxBoost (\x y -> x {functionScoreMaxBoost = y})
+
+functionScoreBoostModeLens :: Lens' FunctionScoreQuery (Maybe BoostMode)
+functionScoreBoostModeLens = lens functionScoreBoostMode (\x y -> x {functionScoreBoostMode = y})
+
+functionScoreMinScoreLens :: Lens' FunctionScoreQuery Score
+functionScoreMinScoreLens = lens functionScoreMinScore (\x y -> x {functionScoreMinScore = y})
+
+functionScoreScoreModeLens :: Lens' FunctionScoreQuery (Maybe ScoreMode)
+functionScoreScoreModeLens = lens functionScoreScoreMode (\x y -> x {functionScoreScoreMode = y})
+
 instance ToJSON FunctionScoreQuery where
   toJSON (FunctionScoreQuery query boost fns maxBoost boostMode minScore scoreMode) =
     omitNulls base
@@ -865,7 +1111,7 @@
           <*> o .:? "boost"
           <*> ( singleFunction o
                   <|> multipleFunctions
-                    `taggedWith` "functions"
+                  `taggedWith` "functions"
               )
           <*> o .:? "max_boost"
           <*> o .:? "boost_mode"
@@ -888,6 +1134,15 @@
   }
   deriving stock (Eq, Show, Generic)
 
+componentScoreFunctionFilterLens :: Lens' ComponentFunctionScoreFunction (Maybe Filter)
+componentScoreFunctionFilterLens = lens componentScoreFunctionFilter (\x y -> x {componentScoreFunctionFilter = y})
+
+componentScoreFunctionLens :: Lens' ComponentFunctionScoreFunction FunctionScoreFunction
+componentScoreFunctionLens = lens componentScoreFunction (\x y -> x {componentScoreFunction = y})
+
+componentScoreFunctionWeightLens :: Lens' ComponentFunctionScoreFunction (Maybe Weight)
+componentScoreFunctionWeightLens = lens componentScoreFunctionWeight (\x y -> x {componentScoreFunctionWeight = y})
+
 instance ToJSON ComponentFunctionScoreFunction where
   toJSON (ComponentFunctionScoreFunction filter' fn weight) =
     omitNulls base
@@ -918,6 +1173,12 @@
     innerHitsSize :: Maybe Integer
   }
   deriving stock (Eq, Show, Generic)
+
+innerHitsFromLens :: Lens' InnerHits (Maybe Integer)
+innerHitsFromLens = lens innerHitsFrom (\x y -> x {innerHitsFrom = y})
+
+innerHitsSizeLens :: Lens' InnerHits (Maybe Integer)
+innerHitsSizeLens = lens innerHitsSize (\x y -> x {innerHitsSize = y})
 
 instance ToJSON InnerHits where
   toJSON (InnerHits ihFrom ihSize) =
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/CommonTerms.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/CommonTerms.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/CommonTerms.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/CommonTerms.hs
@@ -4,6 +4,21 @@
   ( CommonMinimumMatch (..),
     CommonTermsQuery (..),
     MinimumMatchHighLow (..),
+
+    -- * Optics
+    commonTermsQueryFieldLens,
+    commonTermsQueryQueryLens,
+    commonTermsQueryCutoffFrequencyLens,
+    commonTermsQueryLowFreqOperatorLens,
+    commonTermsQueryHighFreqOperatorLens,
+    commonTermsQueryMinimumShouldMatchLens,
+    commonTermsQueryBoostLens,
+    commonTermsQueryAnalyzerLens,
+    commonTermsQueryDisableCoordLens,
+    commonMinimumMatchHighLowPrism,
+    commonMinimumMatchPrism,
+    minimumMatchHighLowLowFreqLens,
+    minimumMatchHighLowHighFreqLens,
   )
 where
 
@@ -25,6 +40,33 @@
   }
   deriving stock (Eq, Show, Generic)
 
+commonTermsQueryFieldLens :: Lens' CommonTermsQuery FieldName
+commonTermsQueryFieldLens = lens commonField (\x y -> x {commonField = y})
+
+commonTermsQueryQueryLens :: Lens' CommonTermsQuery QueryString
+commonTermsQueryQueryLens = lens commonQuery (\x y -> x {commonQuery = y})
+
+commonTermsQueryCutoffFrequencyLens :: Lens' CommonTermsQuery CutoffFrequency
+commonTermsQueryCutoffFrequencyLens = lens commonCutoffFrequency (\x y -> x {commonCutoffFrequency = y})
+
+commonTermsQueryLowFreqOperatorLens :: Lens' CommonTermsQuery BooleanOperator
+commonTermsQueryLowFreqOperatorLens = lens commonLowFreqOperator (\x y -> x {commonLowFreqOperator = y})
+
+commonTermsQueryHighFreqOperatorLens :: Lens' CommonTermsQuery BooleanOperator
+commonTermsQueryHighFreqOperatorLens = lens commonHighFreqOperator (\x y -> x {commonHighFreqOperator = y})
+
+commonTermsQueryMinimumShouldMatchLens :: Lens' CommonTermsQuery (Maybe CommonMinimumMatch)
+commonTermsQueryMinimumShouldMatchLens = lens commonMinimumShouldMatch (\x y -> x {commonMinimumShouldMatch = y})
+
+commonTermsQueryBoostLens :: Lens' CommonTermsQuery (Maybe Boost)
+commonTermsQueryBoostLens = lens commonBoost (\x y -> x {commonBoost = y})
+
+commonTermsQueryAnalyzerLens :: Lens' CommonTermsQuery (Maybe Analyzer)
+commonTermsQueryAnalyzerLens = lens commonAnalyzer (\x y -> x {commonAnalyzer = y})
+
+commonTermsQueryDisableCoordLens :: Lens' CommonTermsQuery (Maybe DisableCoord)
+commonTermsQueryDisableCoordLens = lens commonDisableCoord (\x y -> x {commonDisableCoord = y})
+
 instance ToJSON CommonTermsQuery where
   toJSON
     ( CommonTermsQuery
@@ -70,6 +112,22 @@
   | CommonMinimumMatch MinimumMatch
   deriving stock (Eq, Show, Generic)
 
+commonMinimumMatchHighLowPrism :: Prism' CommonMinimumMatch MinimumMatchHighLow
+commonMinimumMatchHighLowPrism = prism CommonMinimumMatchHighLow extract
+  where
+    extract cmm =
+      case cmm of
+        CommonMinimumMatchHighLow x -> Right x
+        _ -> Left cmm
+
+commonMinimumMatchPrism :: Prism' CommonMinimumMatch MinimumMatch
+commonMinimumMatchPrism = prism CommonMinimumMatch extract
+  where
+    extract cmm =
+      case cmm of
+        CommonMinimumMatch x -> Right x
+        _ -> Left cmm
+
 instance ToJSON CommonMinimumMatch where
   toJSON (CommonMinimumMatch mm) = toJSON mm
   toJSON (CommonMinimumMatchHighLow (MinimumMatchHighLow lowF highF)) =
@@ -99,3 +157,9 @@
     highFreq :: MinimumMatch
   }
   deriving stock (Eq, Show, Generic)
+
+minimumMatchHighLowLowFreqLens :: Lens' MinimumMatchHighLow MinimumMatch
+minimumMatchHighLowLowFreqLens = lens lowFreq (\x y -> x {lowFreq = y})
+
+minimumMatchHighLowHighFreqLens :: Lens' MinimumMatchHighLow MinimumMatch
+minimumMatchHighLowHighFreqLens = lens highFreq (\x y -> x {highFreq = y})
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Fuzzy.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Fuzzy.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Fuzzy.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Fuzzy.hs
@@ -1,10 +1,33 @@
 {-# LANGUAGE OverloadedStrings #-}
 
--- TODO Fuzziness ???
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.Fuzzy
   ( FuzzyQuery (..),
     FuzzyLikeFieldQuery (..),
     FuzzyLikeThisQuery (..),
+
+    -- * Optics
+    fuzzyQueryFieldLens,
+    fuzzyQueryValueLens,
+    fuzzyQueryPrefixLengthLens,
+    fuzzyQueryMaxExpansionsLens,
+    fuzzyQueryFuzzinessLens,
+    fuzzyQueryBoostLens,
+    fuzzyLikeFieldQueryFieldLens,
+    fuzzyLikeFieldQueryTextLens,
+    fuzzyLikeFieldQueryMaxQueryTermsLens,
+    fuzzyLikeFieldQueryIgnoreTermFrequencyLens,
+    fuzzyLikeFieldQueryFuzzinessLens,
+    fuzzyLikeFieldQueryPrefixLengthLens,
+    fuzzyLikeFieldQueryBoostLens,
+    fuzzyLikeFieldQueryAnalyzerLens,
+    fuzzyLikeThisQueryFieldsLens,
+    fuzzyLikeThisQueryTextLens,
+    fuzzyLikeThisQueryMaxQueryTermsLens,
+    fuzzyLikeThisQueryIgnoreTermFrequencyLens,
+    fuzzyLikeThisQueryFuzzinessLens,
+    fuzzyLikeThisQueryPrefixLengthLens,
+    fuzzyLikeThisQueryBoostLens,
+    fuzzyLikeThisQueryAnalyzerLens,
   )
 where
 
@@ -23,6 +46,24 @@
   }
   deriving stock (Eq, Show, Generic)
 
+fuzzyQueryFieldLens :: Lens' FuzzyQuery FieldName
+fuzzyQueryFieldLens = lens fuzzyQueryField (\x y -> x {fuzzyQueryField = y})
+
+fuzzyQueryValueLens :: Lens' FuzzyQuery Text
+fuzzyQueryValueLens = lens fuzzyQueryValue (\x y -> x {fuzzyQueryValue = y})
+
+fuzzyQueryPrefixLengthLens :: Lens' FuzzyQuery PrefixLength
+fuzzyQueryPrefixLengthLens = lens fuzzyQueryPrefixLength (\x y -> x {fuzzyQueryPrefixLength = y})
+
+fuzzyQueryMaxExpansionsLens :: Lens' FuzzyQuery MaxExpansions
+fuzzyQueryMaxExpansionsLens = lens fuzzyQueryMaxExpansions (\x y -> x {fuzzyQueryMaxExpansions = y})
+
+fuzzyQueryFuzzinessLens :: Lens' FuzzyQuery Fuzziness
+fuzzyQueryFuzzinessLens = lens fuzzyQueryFuzziness (\x y -> x {fuzzyQueryFuzziness = y})
+
+fuzzyQueryBoostLens :: Lens' FuzzyQuery (Maybe Boost)
+fuzzyQueryBoostLens = lens fuzzyQueryBoost (\x y -> x {fuzzyQueryBoost = y})
+
 instance ToJSON FuzzyQuery where
   toJSON
     ( FuzzyQuery
@@ -67,6 +108,30 @@
   }
   deriving stock (Eq, Show, Generic)
 
+fuzzyLikeFieldQueryFieldLens :: Lens' FuzzyLikeFieldQuery FieldName
+fuzzyLikeFieldQueryFieldLens = lens fuzzyLikeField (\x y -> x {fuzzyLikeField = y})
+
+fuzzyLikeFieldQueryTextLens :: Lens' FuzzyLikeFieldQuery Text
+fuzzyLikeFieldQueryTextLens = lens fuzzyLikeFieldText (\x y -> x {fuzzyLikeFieldText = y})
+
+fuzzyLikeFieldQueryMaxQueryTermsLens :: Lens' FuzzyLikeFieldQuery MaxQueryTerms
+fuzzyLikeFieldQueryMaxQueryTermsLens = lens fuzzyLikeFieldMaxQueryTerms (\x y -> x {fuzzyLikeFieldMaxQueryTerms = y})
+
+fuzzyLikeFieldQueryIgnoreTermFrequencyLens :: Lens' FuzzyLikeFieldQuery IgnoreTermFrequency
+fuzzyLikeFieldQueryIgnoreTermFrequencyLens = lens fuzzyLikeFieldIgnoreTermFrequency (\x y -> x {fuzzyLikeFieldIgnoreTermFrequency = y})
+
+fuzzyLikeFieldQueryFuzzinessLens :: Lens' FuzzyLikeFieldQuery Fuzziness
+fuzzyLikeFieldQueryFuzzinessLens = lens fuzzyLikeFieldFuzziness (\x y -> x {fuzzyLikeFieldFuzziness = y})
+
+fuzzyLikeFieldQueryPrefixLengthLens :: Lens' FuzzyLikeFieldQuery PrefixLength
+fuzzyLikeFieldQueryPrefixLengthLens = lens fuzzyLikeFieldPrefixLength (\x y -> x {fuzzyLikeFieldPrefixLength = y})
+
+fuzzyLikeFieldQueryBoostLens :: Lens' FuzzyLikeFieldQuery Boost
+fuzzyLikeFieldQueryBoostLens = lens fuzzyLikeFieldBoost (\x y -> x {fuzzyLikeFieldBoost = y})
+
+fuzzyLikeFieldQueryAnalyzerLens :: Lens' FuzzyLikeFieldQuery (Maybe Analyzer)
+fuzzyLikeFieldQueryAnalyzerLens = lens fuzzyLikeFieldAnalyzer (\x y -> x {fuzzyLikeFieldAnalyzer = y})
+
 instance ToJSON FuzzyLikeFieldQuery where
   toJSON
     ( FuzzyLikeFieldQuery
@@ -116,6 +181,30 @@
     fuzzyLikeAnalyzer :: Maybe Analyzer
   }
   deriving stock (Eq, Show, Generic)
+
+fuzzyLikeThisQueryFieldsLens :: Lens' FuzzyLikeThisQuery [FieldName]
+fuzzyLikeThisQueryFieldsLens = lens fuzzyLikeFields (\x y -> x {fuzzyLikeFields = y})
+
+fuzzyLikeThisQueryTextLens :: Lens' FuzzyLikeThisQuery Text
+fuzzyLikeThisQueryTextLens = lens fuzzyLikeText (\x y -> x {fuzzyLikeText = y})
+
+fuzzyLikeThisQueryMaxQueryTermsLens :: Lens' FuzzyLikeThisQuery MaxQueryTerms
+fuzzyLikeThisQueryMaxQueryTermsLens = lens fuzzyLikeMaxQueryTerms (\x y -> x {fuzzyLikeMaxQueryTerms = y})
+
+fuzzyLikeThisQueryIgnoreTermFrequencyLens :: Lens' FuzzyLikeThisQuery IgnoreTermFrequency
+fuzzyLikeThisQueryIgnoreTermFrequencyLens = lens fuzzyLikeIgnoreTermFrequency (\x y -> x {fuzzyLikeIgnoreTermFrequency = y})
+
+fuzzyLikeThisQueryFuzzinessLens :: Lens' FuzzyLikeThisQuery Fuzziness
+fuzzyLikeThisQueryFuzzinessLens = lens fuzzyLikeFuzziness (\x y -> x {fuzzyLikeFuzziness = y})
+
+fuzzyLikeThisQueryPrefixLengthLens :: Lens' FuzzyLikeThisQuery PrefixLength
+fuzzyLikeThisQueryPrefixLengthLens = lens fuzzyLikePrefixLength (\x y -> x {fuzzyLikePrefixLength = y})
+
+fuzzyLikeThisQueryBoostLens :: Lens' FuzzyLikeThisQuery Boost
+fuzzyLikeThisQueryBoostLens = lens fuzzyLikeBoost (\x y -> x {fuzzyLikeBoost = y})
+
+fuzzyLikeThisQueryAnalyzerLens :: Lens' FuzzyLikeThisQuery (Maybe Analyzer)
+fuzzyLikeThisQueryAnalyzerLens = lens fuzzyLikeAnalyzer (\x y -> x {fuzzyLikeAnalyzer = y})
 
 instance ToJSON FuzzyLikeThisQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Match.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Match.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Match.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Match.hs
@@ -7,6 +7,30 @@
     MultiMatchQueryType (..),
     mkMatchQuery,
     mkMultiMatchQuery,
+
+    -- * Optics
+    matchQueryFieldLens,
+    matchQueryQueryStringLens,
+    matchQueryOperatorLens,
+    matchQueryZeroTermsLens,
+    matchQueryCutoffFrequencyLens,
+    matchQueryMatchTypeLens,
+    matchQueryAnalyzerLens,
+    matchQueryMaxExpansionsLens,
+    matchQueryLenientLens,
+    matchQueryBoostLens,
+    matchQueryMinimumShouldMatchLens,
+    matchQueryFuzzinessLens,
+    multiMatchQueryFieldsLens,
+    multiMatchQueryStringLens,
+    multiMatchQueryOperatorLens,
+    multiMatchQueryZeroTermsLens,
+    multiMatchQueryTiebreakerLens,
+    multiMatchQueryTypeLens,
+    multiMatchQueryCutoffFrequencyLens,
+    multiMatchQueryAnalyzerLens,
+    multiMatchQueryMaxExpansionsLens,
+    multiMatchQueryLenientLens,
   )
 where
 
@@ -31,6 +55,42 @@
   }
   deriving stock (Eq, Show, Generic)
 
+matchQueryFieldLens :: Lens' MatchQuery FieldName
+matchQueryFieldLens = lens matchQueryField (\x y -> x {matchQueryField = y})
+
+matchQueryQueryStringLens :: Lens' MatchQuery QueryString
+matchQueryQueryStringLens = lens matchQueryQueryString (\x y -> x {matchQueryQueryString = y})
+
+matchQueryOperatorLens :: Lens' MatchQuery BooleanOperator
+matchQueryOperatorLens = lens matchQueryOperator (\x y -> x {matchQueryOperator = y})
+
+matchQueryZeroTermsLens :: Lens' MatchQuery ZeroTermsQuery
+matchQueryZeroTermsLens = lens matchQueryZeroTerms (\x y -> x {matchQueryZeroTerms = y})
+
+matchQueryCutoffFrequencyLens :: Lens' MatchQuery (Maybe CutoffFrequency)
+matchQueryCutoffFrequencyLens = lens matchQueryCutoffFrequency (\x y -> x {matchQueryCutoffFrequency = y})
+
+matchQueryMatchTypeLens :: Lens' MatchQuery (Maybe MatchQueryType)
+matchQueryMatchTypeLens = lens matchQueryMatchType (\x y -> x {matchQueryMatchType = y})
+
+matchQueryAnalyzerLens :: Lens' MatchQuery (Maybe Analyzer)
+matchQueryAnalyzerLens = lens matchQueryAnalyzer (\x y -> x {matchQueryAnalyzer = y})
+
+matchQueryMaxExpansionsLens :: Lens' MatchQuery (Maybe MaxExpansions)
+matchQueryMaxExpansionsLens = lens matchQueryMaxExpansions (\x y -> x {matchQueryMaxExpansions = y})
+
+matchQueryLenientLens :: Lens' MatchQuery (Maybe Lenient)
+matchQueryLenientLens = lens matchQueryLenient (\x y -> x {matchQueryLenient = y})
+
+matchQueryBoostLens :: Lens' MatchQuery (Maybe Boost)
+matchQueryBoostLens = lens matchQueryBoost (\x y -> x {matchQueryBoost = y})
+
+matchQueryMinimumShouldMatchLens :: Lens' MatchQuery (Maybe Text)
+matchQueryMinimumShouldMatchLens = lens matchQueryMinimumShouldMatch (\x y -> x {matchQueryMinimumShouldMatch = y})
+
+matchQueryFuzzinessLens :: Lens' MatchQuery (Maybe Fuzziness)
+matchQueryFuzzinessLens = lens matchQueryFuzziness (\x y -> x {matchQueryFuzziness = y})
+
 instance ToJSON MatchQuery where
   toJSON
     ( MatchQuery
@@ -114,6 +174,36 @@
     multiMatchQueryLenient :: Maybe Lenient
   }
   deriving stock (Eq, Show, Generic)
+
+multiMatchQueryFieldsLens :: Lens' MultiMatchQuery [FieldName]
+multiMatchQueryFieldsLens = lens multiMatchQueryFields (\x y -> x {multiMatchQueryFields = y})
+
+multiMatchQueryStringLens :: Lens' MultiMatchQuery QueryString
+multiMatchQueryStringLens = lens multiMatchQueryString (\x y -> x {multiMatchQueryString = y})
+
+multiMatchQueryOperatorLens :: Lens' MultiMatchQuery BooleanOperator
+multiMatchQueryOperatorLens = lens multiMatchQueryOperator (\x y -> x {multiMatchQueryOperator = y})
+
+multiMatchQueryZeroTermsLens :: Lens' MultiMatchQuery ZeroTermsQuery
+multiMatchQueryZeroTermsLens = lens multiMatchQueryZeroTerms (\x y -> x {multiMatchQueryZeroTerms = y})
+
+multiMatchQueryTiebreakerLens :: Lens' MultiMatchQuery (Maybe Tiebreaker)
+multiMatchQueryTiebreakerLens = lens multiMatchQueryTiebreaker (\x y -> x {multiMatchQueryTiebreaker = y})
+
+multiMatchQueryTypeLens :: Lens' MultiMatchQuery (Maybe MultiMatchQueryType)
+multiMatchQueryTypeLens = lens multiMatchQueryType (\x y -> x {multiMatchQueryType = y})
+
+multiMatchQueryCutoffFrequencyLens :: Lens' MultiMatchQuery (Maybe CutoffFrequency)
+multiMatchQueryCutoffFrequencyLens = lens multiMatchQueryCutoffFrequency (\x y -> x {multiMatchQueryCutoffFrequency = y})
+
+multiMatchQueryAnalyzerLens :: Lens' MultiMatchQuery (Maybe Analyzer)
+multiMatchQueryAnalyzerLens = lens multiMatchQueryAnalyzer (\x y -> x {multiMatchQueryAnalyzer = y})
+
+multiMatchQueryMaxExpansionsLens :: Lens' MultiMatchQuery (Maybe MaxExpansions)
+multiMatchQueryMaxExpansionsLens = lens multiMatchQueryMaxExpansions (\x y -> x {multiMatchQueryMaxExpansions = y})
+
+multiMatchQueryLenientLens :: Lens' MultiMatchQuery (Maybe Lenient)
+multiMatchQueryLenientLens = lens multiMatchQueryLenient (\x y -> x {multiMatchQueryLenient = y})
 
 instance ToJSON MultiMatchQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThis.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThis.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThis.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThis.hs
@@ -2,6 +2,21 @@
 
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.MoreLikeThis
   ( MoreLikeThisQuery (..),
+
+    -- * Optics
+    moreLikeThisQueryTextLens,
+    moreLikeThisQueryFieldsLens,
+    moreLikeThisQueryPercentMatchLens,
+    moreLikeThisQueryMinimumTermFreqLens,
+    moreLikeThisQueryMaxQueryTermsLens,
+    moreLikeThisQueryStopWordsLens,
+    moreLikeThisQueryMinDocFrequencyLens,
+    moreLikeThisQueryMaxDocFrequencyLens,
+    moreLikeThisQueryMinWordLengthLens,
+    moreLikeThisQueryMaxWordLengthLens,
+    moreLikeThisQueryBoostTermsLens,
+    moreLikeThisQueryBoostLens,
+    moreLikeThisQueryAnalyzerLens,
   )
 where
 
@@ -26,6 +41,45 @@
     moreLikeThisAnalyzer :: Maybe Analyzer
   }
   deriving stock (Eq, Show, Generic)
+
+moreLikeThisQueryTextLens :: Lens' MoreLikeThisQuery (Text)
+moreLikeThisQueryTextLens = lens moreLikeThisText (\x y -> x {moreLikeThisText = y})
+
+moreLikeThisQueryFieldsLens :: Lens' MoreLikeThisQuery (Maybe (NonEmpty FieldName))
+moreLikeThisQueryFieldsLens = lens moreLikeThisFields (\x y -> x {moreLikeThisFields = y})
+
+moreLikeThisQueryPercentMatchLens :: Lens' MoreLikeThisQuery (Maybe PercentMatch)
+moreLikeThisQueryPercentMatchLens = lens moreLikeThisPercentMatch (\x y -> x {moreLikeThisPercentMatch = y})
+
+moreLikeThisQueryMinimumTermFreqLens :: Lens' MoreLikeThisQuery (Maybe MinimumTermFrequency)
+moreLikeThisQueryMinimumTermFreqLens = lens moreLikeThisMinimumTermFreq (\x y -> x {moreLikeThisMinimumTermFreq = y})
+
+moreLikeThisQueryMaxQueryTermsLens :: Lens' MoreLikeThisQuery (Maybe MaxQueryTerms)
+moreLikeThisQueryMaxQueryTermsLens = lens moreLikeThisMaxQueryTerms (\x y -> x {moreLikeThisMaxQueryTerms = y})
+
+moreLikeThisQueryStopWordsLens :: Lens' MoreLikeThisQuery (Maybe (NonEmpty StopWord))
+moreLikeThisQueryStopWordsLens = lens moreLikeThisStopWords (\x y -> x {moreLikeThisStopWords = y})
+
+moreLikeThisQueryMinDocFrequencyLens :: Lens' MoreLikeThisQuery (Maybe MinDocFrequency)
+moreLikeThisQueryMinDocFrequencyLens = lens moreLikeThisMinDocFrequency (\x y -> x {moreLikeThisMinDocFrequency = y})
+
+moreLikeThisQueryMaxDocFrequencyLens :: Lens' MoreLikeThisQuery (Maybe MaxDocFrequency)
+moreLikeThisQueryMaxDocFrequencyLens = lens moreLikeThisMaxDocFrequency (\x y -> x {moreLikeThisMaxDocFrequency = y})
+
+moreLikeThisQueryMinWordLengthLens :: Lens' MoreLikeThisQuery (Maybe MinWordLength)
+moreLikeThisQueryMinWordLengthLens = lens moreLikeThisMinWordLength (\x y -> x {moreLikeThisMinWordLength = y})
+
+moreLikeThisQueryMaxWordLengthLens :: Lens' MoreLikeThisQuery (Maybe MaxWordLength)
+moreLikeThisQueryMaxWordLengthLens = lens moreLikeThisMaxWordLength (\x y -> x {moreLikeThisMaxWordLength = y})
+
+moreLikeThisQueryBoostTermsLens :: Lens' MoreLikeThisQuery (Maybe BoostTerms)
+moreLikeThisQueryBoostTermsLens = lens moreLikeThisBoostTerms (\x y -> x {moreLikeThisBoostTerms = y})
+
+moreLikeThisQueryBoostLens :: Lens' MoreLikeThisQuery (Maybe Boost)
+moreLikeThisQueryBoostLens = lens moreLikeThisBoost (\x y -> x {moreLikeThisBoost = y})
+
+moreLikeThisQueryAnalyzerLens :: Lens' MoreLikeThisQuery (Maybe Analyzer)
+moreLikeThisQueryAnalyzerLens = lens moreLikeThisAnalyzer (\x y -> x {moreLikeThisAnalyzer = y})
 
 instance ToJSON MoreLikeThisQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThisField.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThisField.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThisField.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/MoreLikeThisField.hs
@@ -2,6 +2,21 @@
 
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.MoreLikeThisField
   ( MoreLikeThisFieldQuery (..),
+
+    -- * Optics
+    moreLikeThisFieldQueryTextLens,
+    moreLikeThisFieldQueryFieldsLens,
+    moreLikeThisFieldQueryPercentMatchLens,
+    moreLikeThisFieldQueryMinimumTermFreqLens,
+    moreLikeThisFieldQueryMaxQueryTermsLens,
+    moreLikeThisFieldQueryStopWordsLens,
+    moreLikeThisFieldQueryMinDocFrequencyLens,
+    moreLikeThisFieldQueryMaxDocFrequencyLens,
+    moreLikeThisFieldQueryMinWordLengthLens,
+    moreLikeThisFieldQueryMaxWordLengthLens,
+    moreLikeThisFieldQueryBoostTermsLens,
+    moreLikeThisFieldQueryBoostLens,
+    moreLikeThisFieldQueryAnalyzerLens,
   )
 where
 
@@ -27,6 +42,45 @@
     moreLikeThisFieldAnalyzer :: Maybe Analyzer
   }
   deriving stock (Eq, Show, Generic)
+
+moreLikeThisFieldQueryTextLens :: Lens' MoreLikeThisFieldQuery Text
+moreLikeThisFieldQueryTextLens = lens moreLikeThisFieldText (\x y -> x {moreLikeThisFieldText = y})
+
+moreLikeThisFieldQueryFieldsLens :: Lens' MoreLikeThisFieldQuery FieldName
+moreLikeThisFieldQueryFieldsLens = lens moreLikeThisFieldFields (\x y -> x {moreLikeThisFieldFields = y})
+
+moreLikeThisFieldQueryPercentMatchLens :: Lens' MoreLikeThisFieldQuery (Maybe PercentMatch)
+moreLikeThisFieldQueryPercentMatchLens = lens moreLikeThisFieldPercentMatch (\x y -> x {moreLikeThisFieldPercentMatch = y})
+
+moreLikeThisFieldQueryMinimumTermFreqLens :: Lens' MoreLikeThisFieldQuery (Maybe MinimumTermFrequency)
+moreLikeThisFieldQueryMinimumTermFreqLens = lens moreLikeThisFieldMinimumTermFreq (\x y -> x {moreLikeThisFieldMinimumTermFreq = y})
+
+moreLikeThisFieldQueryMaxQueryTermsLens :: Lens' MoreLikeThisFieldQuery (Maybe MaxQueryTerms)
+moreLikeThisFieldQueryMaxQueryTermsLens = lens moreLikeThisFieldMaxQueryTerms (\x y -> x {moreLikeThisFieldMaxQueryTerms = y})
+
+moreLikeThisFieldQueryStopWordsLens :: Lens' MoreLikeThisFieldQuery (Maybe (NonEmpty StopWord))
+moreLikeThisFieldQueryStopWordsLens = lens moreLikeThisFieldStopWords (\x y -> x {moreLikeThisFieldStopWords = y})
+
+moreLikeThisFieldQueryMinDocFrequencyLens :: Lens' MoreLikeThisFieldQuery (Maybe MinDocFrequency)
+moreLikeThisFieldQueryMinDocFrequencyLens = lens moreLikeThisFieldMinDocFrequency (\x y -> x {moreLikeThisFieldMinDocFrequency = y})
+
+moreLikeThisFieldQueryMaxDocFrequencyLens :: Lens' MoreLikeThisFieldQuery (Maybe MaxDocFrequency)
+moreLikeThisFieldQueryMaxDocFrequencyLens = lens moreLikeThisFieldMaxDocFrequency (\x y -> x {moreLikeThisFieldMaxDocFrequency = y})
+
+moreLikeThisFieldQueryMinWordLengthLens :: Lens' MoreLikeThisFieldQuery (Maybe MinWordLength)
+moreLikeThisFieldQueryMinWordLengthLens = lens moreLikeThisFieldMinWordLength (\x y -> x {moreLikeThisFieldMinWordLength = y})
+
+moreLikeThisFieldQueryMaxWordLengthLens :: Lens' MoreLikeThisFieldQuery (Maybe MaxWordLength)
+moreLikeThisFieldQueryMaxWordLengthLens = lens moreLikeThisFieldMaxWordLength (\x y -> x {moreLikeThisFieldMaxWordLength = y})
+
+moreLikeThisFieldQueryBoostTermsLens :: Lens' MoreLikeThisFieldQuery (Maybe BoostTerms)
+moreLikeThisFieldQueryBoostTermsLens = lens moreLikeThisFieldBoostTerms (\x y -> x {moreLikeThisFieldBoostTerms = y})
+
+moreLikeThisFieldQueryBoostLens :: Lens' MoreLikeThisFieldQuery (Maybe Boost)
+moreLikeThisFieldQueryBoostLens = lens moreLikeThisFieldBoost (\x y -> x {moreLikeThisFieldBoost = y})
+
+moreLikeThisFieldQueryAnalyzerLens :: Lens' MoreLikeThisFieldQuery (Maybe Analyzer)
+moreLikeThisFieldQueryAnalyzerLens = lens moreLikeThisFieldAnalyzer (\x y -> x {moreLikeThisFieldAnalyzer = y})
 
 instance ToJSON MoreLikeThisFieldQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Prefix.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Prefix.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Prefix.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Prefix.hs
@@ -2,6 +2,11 @@
 
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.Prefix
   ( PrefixQuery (..),
+
+    -- * Optics
+    prefixQueryFieldLens,
+    prefixQueryPrefixValueLens,
+    prefixQueryBoostLens,
   )
 where
 
@@ -16,6 +21,15 @@
     prefixQueryBoost :: Maybe Boost
   }
   deriving stock (Eq, Show, Generic)
+
+prefixQueryFieldLens :: Lens' PrefixQuery FieldName
+prefixQueryFieldLens = lens prefixQueryField (\x y -> x {prefixQueryField = y})
+
+prefixQueryPrefixValueLens :: Lens' PrefixQuery Text
+prefixQueryPrefixValueLens = lens prefixQueryPrefixValue (\x y -> x {prefixQueryPrefixValue = y})
+
+prefixQueryBoostLens :: Lens' PrefixQuery (Maybe Boost)
+prefixQueryBoostLens = lens prefixQueryBoost (\x y -> x {prefixQueryBoost = y})
 
 instance ToJSON PrefixQuery where
   toJSON (PrefixQuery (FieldName fieldName) queryValue boost) =
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/QueryString.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/QueryString.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/QueryString.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/QueryString.hs
@@ -3,6 +3,25 @@
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.QueryString
   ( QueryStringQuery (..),
     mkQueryStringQuery,
+
+    -- * Optics
+    queryStringQueryQueryLens,
+    queryStringQueryDefaultFieldLens,
+    queryStringQueryOperatorLens,
+    queryStringQueryAnalyzerLens,
+    queryStringQueryAllowLeadingWildcardLens,
+    queryStringQueryLowercaseExpandedLens,
+    queryStringQueryEnablePositionIncrementsLens,
+    queryStringQueryFuzzyMaxExpansionsLens,
+    queryStringQueryFuzzinessLens,
+    queryStringQueryFuzzyPrefixLengthLens,
+    queryStringQueryPhraseSlopLens,
+    queryStringQueryBoostLens,
+    queryStringQueryAnalyzeWildcardLens,
+    queryStringQueryGeneratePhraseQueriesLens,
+    queryStringQueryMinimumShouldMatchLens,
+    queryStringQueryLenientLens,
+    queryStringQueryLocaleLens,
   )
 where
 
@@ -32,6 +51,57 @@
     queryStringLocale :: Maybe Locale
   }
   deriving stock (Eq, Show, Generic)
+
+queryStringQueryQueryLens :: Lens' QueryStringQuery QueryString
+queryStringQueryQueryLens = lens queryStringQuery (\x y -> x {queryStringQuery = y})
+
+queryStringQueryDefaultFieldLens :: Lens' QueryStringQuery (Maybe FieldName)
+queryStringQueryDefaultFieldLens = lens queryStringDefaultField (\x y -> x {queryStringDefaultField = y})
+
+queryStringQueryOperatorLens :: Lens' QueryStringQuery (Maybe BooleanOperator)
+queryStringQueryOperatorLens = lens queryStringOperator (\x y -> x {queryStringOperator = y})
+
+queryStringQueryAnalyzerLens :: Lens' QueryStringQuery (Maybe Analyzer)
+queryStringQueryAnalyzerLens = lens queryStringAnalyzer (\x y -> x {queryStringAnalyzer = y})
+
+queryStringQueryAllowLeadingWildcardLens :: Lens' QueryStringQuery (Maybe AllowLeadingWildcard)
+queryStringQueryAllowLeadingWildcardLens = lens queryStringAllowLeadingWildcard (\x y -> x {queryStringAllowLeadingWildcard = y})
+
+queryStringQueryLowercaseExpandedLens :: Lens' QueryStringQuery (Maybe LowercaseExpanded)
+queryStringQueryLowercaseExpandedLens = lens queryStringLowercaseExpanded (\x y -> x {queryStringLowercaseExpanded = y})
+
+queryStringQueryEnablePositionIncrementsLens :: Lens' QueryStringQuery (Maybe EnablePositionIncrements)
+queryStringQueryEnablePositionIncrementsLens = lens queryStringEnablePositionIncrements (\x y -> x {queryStringEnablePositionIncrements = y})
+
+queryStringQueryFuzzyMaxExpansionsLens :: Lens' QueryStringQuery (Maybe MaxExpansions)
+queryStringQueryFuzzyMaxExpansionsLens = lens queryStringFuzzyMaxExpansions (\x y -> x {queryStringFuzzyMaxExpansions = y})
+
+queryStringQueryFuzzinessLens :: Lens' QueryStringQuery (Maybe Fuzziness)
+queryStringQueryFuzzinessLens = lens queryStringFuzziness (\x y -> x {queryStringFuzziness = y})
+
+queryStringQueryFuzzyPrefixLengthLens :: Lens' QueryStringQuery (Maybe PrefixLength)
+queryStringQueryFuzzyPrefixLengthLens = lens queryStringFuzzyPrefixLength (\x y -> x {queryStringFuzzyPrefixLength = y})
+
+queryStringQueryPhraseSlopLens :: Lens' QueryStringQuery (Maybe PhraseSlop)
+queryStringQueryPhraseSlopLens = lens queryStringPhraseSlop (\x y -> x {queryStringPhraseSlop = y})
+
+queryStringQueryBoostLens :: Lens' QueryStringQuery (Maybe Boost)
+queryStringQueryBoostLens = lens queryStringBoost (\x y -> x {queryStringBoost = y})
+
+queryStringQueryAnalyzeWildcardLens :: Lens' QueryStringQuery (Maybe AnalyzeWildcard)
+queryStringQueryAnalyzeWildcardLens = lens queryStringAnalyzeWildcard (\x y -> x {queryStringAnalyzeWildcard = y})
+
+queryStringQueryGeneratePhraseQueriesLens :: Lens' QueryStringQuery (Maybe GeneratePhraseQueries)
+queryStringQueryGeneratePhraseQueriesLens = lens queryStringGeneratePhraseQueries (\x y -> x {queryStringGeneratePhraseQueries = y})
+
+queryStringQueryMinimumShouldMatchLens :: Lens' QueryStringQuery (Maybe MinimumMatch)
+queryStringQueryMinimumShouldMatchLens = lens queryStringMinimumShouldMatch (\x y -> x {queryStringMinimumShouldMatch = y})
+
+queryStringQueryLenientLens :: Lens' QueryStringQuery (Maybe Lenient)
+queryStringQueryLenientLens = lens queryStringLenient (\x y -> x {queryStringLenient = y})
+
+queryStringQueryLocaleLens :: Lens' QueryStringQuery (Maybe Locale)
+queryStringQueryLocaleLens = lens queryStringLocale (\x y -> x {queryStringLocale = y})
 
 instance ToJSON QueryStringQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Range.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Range.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Range.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Range.hs
@@ -12,6 +12,11 @@
     RangeQuery (..),
     RangeValue (..),
     mkRangeQuery,
+
+    -- * Optics
+    rangeQueryFieldLens,
+    rangeQueryRangeLens,
+    rangeQueryBoostLens,
   )
 where
 
@@ -26,6 +31,15 @@
     rangeQueryBoost :: Boost
   }
   deriving stock (Eq, Show, Generic)
+
+rangeQueryFieldLens :: Lens' RangeQuery FieldName
+rangeQueryFieldLens = lens rangeQueryField (\x y -> x {rangeQueryField = y})
+
+rangeQueryRangeLens :: Lens' RangeQuery RangeValue
+rangeQueryRangeLens = lens rangeQueryRange (\x y -> x {rangeQueryRange = y})
+
+rangeQueryBoostLens :: Lens' RangeQuery Boost
+rangeQueryBoostLens = lens rangeQueryBoost (\x y -> x {rangeQueryBoost = y})
 
 instance ToJSON RangeQuery where
   toJSON (RangeQuery (FieldName fieldName) range boost) =
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Regexp.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Regexp.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Regexp.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Regexp.hs
@@ -5,6 +5,12 @@
     RegexpFlag (..),
     RegexpFlags (..),
     RegexpQuery (..),
+
+    -- * Optics
+    regexpQueryFieldLens,
+    regexpQueryLens,
+    regexpQueryFlagsLens,
+    regexpQueryBoostLens,
   )
 where
 
@@ -21,6 +27,18 @@
     regexpQueryBoost :: Maybe Boost
   }
   deriving stock (Eq, Show, Generic)
+
+regexpQueryFieldLens :: Lens' RegexpQuery FieldName
+regexpQueryFieldLens = lens regexpQueryField (\x y -> x {regexpQueryField = y})
+
+regexpQueryLens :: Lens' RegexpQuery Regexp
+regexpQueryLens = lens regexpQuery (\x y -> x {regexpQuery = y})
+
+regexpQueryFlagsLens :: Lens' RegexpQuery RegexpFlags
+regexpQueryFlagsLens = lens regexpQueryFlags (\x y -> x {regexpQueryFlags = y})
+
+regexpQueryBoostLens :: Lens' RegexpQuery (Maybe Boost)
+regexpQueryBoostLens = lens regexpQueryBoost (\x y -> x {regexpQueryBoost = y})
 
 instance ToJSON RegexpQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/SimpleQueryString.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/SimpleQueryString.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/SimpleQueryString.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/SimpleQueryString.hs
@@ -5,6 +5,15 @@
   ( FieldOrFields (..),
     SimpleQueryFlag (..),
     SimpleQueryStringQuery (..),
+
+    -- * Optics
+    simpleQueryStringQueryQueryLens,
+    simpleQueryStringQueryFieldLens,
+    simpleQueryStringQueryOperatorLens,
+    simpleQueryStringQueryAnalyzerLens,
+    simpleQueryStringQueryFlagsLens,
+    simpleQueryStringQueryLowercaseExpandedLens,
+    simpleQueryStringQueryLocaleLens,
   )
 where
 
@@ -24,6 +33,27 @@
   }
   deriving stock (Eq, Show, Generic)
 
+simpleQueryStringQueryQueryLens :: Lens' SimpleQueryStringQuery QueryString
+simpleQueryStringQueryQueryLens = lens simpleQueryStringQuery (\x y -> x {simpleQueryStringQuery = y})
+
+simpleQueryStringQueryFieldLens :: Lens' SimpleQueryStringQuery (Maybe FieldOrFields)
+simpleQueryStringQueryFieldLens = lens simpleQueryStringField (\x y -> x {simpleQueryStringField = y})
+
+simpleQueryStringQueryOperatorLens :: Lens' SimpleQueryStringQuery (Maybe BooleanOperator)
+simpleQueryStringQueryOperatorLens = lens simpleQueryStringOperator (\x y -> x {simpleQueryStringOperator = y})
+
+simpleQueryStringQueryAnalyzerLens :: Lens' SimpleQueryStringQuery (Maybe Analyzer)
+simpleQueryStringQueryAnalyzerLens = lens simpleQueryStringAnalyzer (\x y -> x {simpleQueryStringAnalyzer = y})
+
+simpleQueryStringQueryFlagsLens :: Lens' SimpleQueryStringQuery (Maybe (NonEmpty SimpleQueryFlag))
+simpleQueryStringQueryFlagsLens = lens simpleQueryStringFlags (\x y -> x {simpleQueryStringFlags = y})
+
+simpleQueryStringQueryLowercaseExpandedLens :: Lens' SimpleQueryStringQuery (Maybe LowercaseExpanded)
+simpleQueryStringQueryLowercaseExpandedLens = lens simpleQueryStringLowercaseExpanded (\x y -> x {simpleQueryStringLowercaseExpanded = y})
+
+simpleQueryStringQueryLocaleLens :: Lens' SimpleQueryStringQuery (Maybe Locale)
+simpleQueryStringQueryLocaleLens = lens simpleQueryStringLocale (\x y -> x {simpleQueryStringLocale = y})
+
 instance ToJSON SimpleQueryStringQuery where
   toJSON SimpleQueryStringQuery {..} =
     omitNulls (base ++ maybeAdd)
@@ -112,5 +142,7 @@
 
 instance FromJSON FieldOrFields where
   parseJSON v =
-    FofField <$> parseJSON v
-      <|> FofFields <$> (parseNEJSON =<< parseJSON v)
+    FofField
+      <$> parseJSON v
+        <|> FofFields
+      <$> (parseNEJSON =<< parseJSON v)
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Wildcard.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Wildcard.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Wildcard.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Query/Wildcard.hs
@@ -2,6 +2,11 @@
 
 module Database.Bloodhound.Internal.Versions.Common.Types.Query.Wildcard
   ( WildcardQuery (..),
+
+    -- * Optics
+    wildcardQueryFieldLens,
+    wildcardQueryLens,
+    wildcardQueryBoostLens,
   )
 where
 
@@ -16,6 +21,15 @@
     wildcardQueryBoost :: Maybe Boost
   }
   deriving stock (Eq, Show, Generic)
+
+wildcardQueryFieldLens :: Lens' WildcardQuery FieldName
+wildcardQueryFieldLens = lens wildcardQueryField (\x y -> x {wildcardQueryField = y})
+
+wildcardQueryLens :: Lens' WildcardQuery Key
+wildcardQueryLens = lens wildcardQuery (\x y -> x {wildcardQuery = y})
+
+wildcardQueryBoostLens :: Lens' WildcardQuery (Maybe Boost)
+wildcardQueryBoostLens = lens wildcardQueryBoost (\x y -> x {wildcardQueryBoost = y})
 
 instance ToJSON WildcardQuery where
   toJSON
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Reindex.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Reindex.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Reindex.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Reindex.hs
@@ -39,17 +39,17 @@
       <*> v .: "dest"
       <*> v .:? "script"
 
-reindexConflictsLens :: Lens' ReindexRequest (Maybe ReindexConflicts)
-reindexConflictsLens = lens reindexConflicts (\x y -> x {reindexConflicts = y})
+reindexRequestConflictsLens :: Lens' ReindexRequest (Maybe ReindexConflicts)
+reindexRequestConflictsLens = lens reindexConflicts (\x y -> x {reindexConflicts = y})
 
-reindexSourceLens :: Lens' ReindexRequest ReindexSource
-reindexSourceLens = lens reindexSource (\x y -> x {reindexSource = y})
+reindexRequestSourceLens :: Lens' ReindexRequest ReindexSource
+reindexRequestSourceLens = lens reindexSource (\x y -> x {reindexSource = y})
 
-reindexDestLens :: Lens' ReindexRequest ReindexDest
-reindexDestLens = lens reindexDest (\x y -> x {reindexDest = y})
+reindexRequestDestLens :: Lens' ReindexRequest ReindexDest
+reindexRequestDestLens = lens reindexDest (\x y -> x {reindexDest = y})
 
-reindexScriptLens :: Lens' ReindexRequest (Maybe ReindexScript)
-reindexScriptLens = lens reindexScript (\x y -> x {reindexScript = y})
+reindexRequestScriptLens :: Lens' ReindexRequest (Maybe ReindexScript)
+reindexRequestScriptLens = lens reindexScript (\x y -> x {reindexScript = y})
 
 data ReindexConflicts
   = ReindexAbortOnConflicts
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Snapshots.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Snapshots.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Snapshots.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Snapshots.hs
@@ -37,50 +37,50 @@
 
     -- * Optics
     snapshotRepoNameLens,
-    gSnapshotRepoNameLens,
-    gSnapshotRepoTypeLens,
-    gSnapshotRepoSettingsLens,
+    genericSnapshotRepoNameLens,
+    genericSnapshotRepoTypeLens,
+    genericSnapshotRepoSettingsLens,
     snapshotRepoTypeLens,
-    gSnapshotRepoSettingsObjectLens,
+    genericSnapshotRepoSettingsObjectLens,
     snapshotNodeVerificationsLens,
-    snvFullIdLens,
-    snvNodeNameLens,
-    snapRestoreWaitForCompletionLens,
-    snapRestoreIndicesLens,
-    snapRestoreIgnoreUnavailableLens,
-    snapRestoreIncludeGlobalStateLens,
-    snapRestoreRenamePatternLens,
-    snapRestoreRenameReplacementLens,
-    snapRestorePartialLens,
-    snapRestoreIncludeAliasesLens,
-    snapRestoreIndexSettingsOverridesLens,
-    snapRestoreIgnoreIndexSettingsLens,
-    repoUpdateVerifyLens,
-    fsrNameLens,
-    fsrLocationLens,
-    fsrCompressMetadataLens,
-    fsrChunkSizeLens,
-    fsrMaxRestoreBytesPerSecLens,
-    fsrMaxSnapshotBytesPerSecLens,
-    snapWaitForCompletionLens,
-    snapIndicesLens,
-    snapIgnoreUnavailableLens,
-    snapIncludeGlobalStateLens,
-    snapPartialLens,
-    snapInfoShardsLens,
-    snapInfoFailuresLens,
-    snapInfoDurationLens,
-    snapInfoEndTimeLens,
-    snapInfoStartTimeLens,
-    snapInfoStateLens,
-    snapInfoIndicesLens,
-    snapInfoNameLens,
-    snapShardFailureIndexLens,
-    snapShardFailureNodeIdLens,
-    snapShardFailureReasonLens,
-    snapShardFailureShardIdLens,
-    rrPatternLens,
-    restoreOverrideReplicasLens,
+    snapshotNodeVerificationFullIdLens,
+    snapshotNodeVerificationNodeNameLens,
+    snapshotRestoreSettingsWaitForCompletionLens,
+    snapshotRestoreSettingsIndicesLens,
+    snapshotRestoreSettingsIgnoreUnavailableLens,
+    snapshotRestoreSettingsIncludeGlobalStateLens,
+    snapshotRestoreSettingsRenamePatternLens,
+    snapshotRestoreSettingsRenameReplacementLens,
+    snapshotRestoreSettingsPartialLens,
+    snapshotRestoreSettingsIncludeAliasesLens,
+    snapshotRestoreSettingsIndexSettingsOverridesLens,
+    snapshotRestoreSettingsIgnoreIndexSettingsLens,
+    snapshotRepoUpdateSettingsUpdateVerifyLens,
+    fsSnapshotRepoNameLens,
+    fsSnapshotRepoLocationLens,
+    fsSnapshotRepoCompressMetadataLens,
+    fsSnapshotRepoChunkSizeLens,
+    fsSnapshotRepoMaxRestoreBytesPerSecLens,
+    fsSnapshotRepoMaxSnapshotBytesPerSecLens,
+    snapshotCreateSettingsWaitForCompletionLens,
+    snapshotCreateSettingsIndicesLens,
+    snapshotCreateSettingsIgnoreUnavailableLens,
+    snapshotCreateSettingsIncludeGlobalStateLens,
+    snapshotCreateSettingsPartialLens,
+    snapshotInfoShardsLens,
+    snapshotInfoFailuresLens,
+    snapshotInfoDurationLens,
+    snapshotInfoEndTimeLens,
+    snapshotInfoStartTimeLens,
+    snapshotInfoStateLens,
+    snapshotInfoIndicesLens,
+    snapshotInfoNameLens,
+    snapshotShardFailureIndexLens,
+    snapshotShardFailureNodeIdLens,
+    snapshotShardFailureReasonLens,
+    snapshotShardFailureShardIdLens,
+    restoreRenamePatternLens,
+    restoreIndexSettingsOverrideReplicasLens,
   )
 where
 
@@ -133,14 +133,14 @@
   toGSnapshotRepo = id
   fromGSnapshotRepo = Right
 
-gSnapshotRepoNameLens :: Lens' GenericSnapshotRepo SnapshotRepoName
-gSnapshotRepoNameLens = lens gSnapshotRepoName (\x y -> x {gSnapshotRepoName = y})
+genericSnapshotRepoNameLens :: Lens' GenericSnapshotRepo SnapshotRepoName
+genericSnapshotRepoNameLens = lens gSnapshotRepoName (\x y -> x {gSnapshotRepoName = y})
 
-gSnapshotRepoTypeLens :: Lens' GenericSnapshotRepo SnapshotRepoType
-gSnapshotRepoTypeLens = lens gSnapshotRepoType (\x y -> x {gSnapshotRepoType = y})
+genericSnapshotRepoTypeLens :: Lens' GenericSnapshotRepo SnapshotRepoType
+genericSnapshotRepoTypeLens = lens gSnapshotRepoType (\x y -> x {gSnapshotRepoType = y})
 
-gSnapshotRepoSettingsLens :: Lens' GenericSnapshotRepo GenericSnapshotRepoSettings
-gSnapshotRepoSettingsLens = lens gSnapshotRepoSettings (\x y -> x {gSnapshotRepoSettings = y})
+genericSnapshotRepoSettingsLens :: Lens' GenericSnapshotRepo GenericSnapshotRepoSettings
+genericSnapshotRepoSettingsLens = lens gSnapshotRepoSettings (\x y -> x {gSnapshotRepoSettings = y})
 
 newtype SnapshotRepoType = SnapshotRepoType {snapshotRepoType :: Text}
   deriving newtype (Eq, Ord, Show, ToJSON, FromJSON)
@@ -159,8 +159,8 @@
 instance FromJSON GenericSnapshotRepoSettings where
   parseJSON = fmap (GenericSnapshotRepoSettings . fmap unStringlyTypeJSON) . parseJSON
 
-gSnapshotRepoSettingsObjectLens :: Lens' GenericSnapshotRepoSettings Object
-gSnapshotRepoSettingsObjectLens = lens gSnapshotRepoSettingsObject (\x y -> x {gSnapshotRepoSettingsObject = y})
+genericSnapshotRepoSettingsObjectLens :: Lens' GenericSnapshotRepoSettings Object
+genericSnapshotRepoSettingsObjectLens = lens gSnapshotRepoSettingsObject (\x y -> x {gSnapshotRepoSettingsObject = y})
 
 -- | The result of running 'verifySnapshotRepo'.
 newtype SnapshotVerification = SnapshotVerification
@@ -187,11 +187,11 @@
   }
   deriving stock (Eq, Show)
 
-snvFullIdLens :: Lens' SnapshotNodeVerification FullNodeId
-snvFullIdLens = lens snvFullId (\x y -> x {snvFullId = y})
+snapshotNodeVerificationFullIdLens :: Lens' SnapshotNodeVerification FullNodeId
+snapshotNodeVerificationFullIdLens = lens snvFullId (\x y -> x {snvFullId = y})
 
-snvNodeNameLens :: Lens' SnapshotNodeVerification NodeName
-snvNodeNameLens = lens snvNodeName (\x y -> x {snvNodeName = y})
+snapshotNodeVerificationNodeNameLens :: Lens' SnapshotNodeVerification NodeName
+snapshotNodeVerificationNodeNameLens = lens snvNodeName (\x y -> x {snvNodeName = y})
 
 data SnapshotState
   = SnapshotInit
@@ -256,35 +256,35 @@
   }
   deriving stock (Eq, Show)
 
-snapRestoreWaitForCompletionLens :: Lens' SnapshotRestoreSettings Bool
-snapRestoreWaitForCompletionLens = lens snapRestoreWaitForCompletion (\x y -> x {snapRestoreWaitForCompletion = y})
+snapshotRestoreSettingsWaitForCompletionLens :: Lens' SnapshotRestoreSettings Bool
+snapshotRestoreSettingsWaitForCompletionLens = lens snapRestoreWaitForCompletion (\x y -> x {snapRestoreWaitForCompletion = y})
 
-snapRestoreIndicesLens :: Lens' SnapshotRestoreSettings (Maybe IndexSelection)
-snapRestoreIndicesLens = lens snapRestoreIndices (\x y -> x {snapRestoreIndices = y})
+snapshotRestoreSettingsIndicesLens :: Lens' SnapshotRestoreSettings (Maybe IndexSelection)
+snapshotRestoreSettingsIndicesLens = lens snapRestoreIndices (\x y -> x {snapRestoreIndices = y})
 
-snapRestoreIgnoreUnavailableLens :: Lens' SnapshotRestoreSettings Bool
-snapRestoreIgnoreUnavailableLens = lens snapRestoreIgnoreUnavailable (\x y -> x {snapRestoreIgnoreUnavailable = y})
+snapshotRestoreSettingsIgnoreUnavailableLens :: Lens' SnapshotRestoreSettings Bool
+snapshotRestoreSettingsIgnoreUnavailableLens = lens snapRestoreIgnoreUnavailable (\x y -> x {snapRestoreIgnoreUnavailable = y})
 
-snapRestoreIncludeGlobalStateLens :: Lens' SnapshotRestoreSettings Bool
-snapRestoreIncludeGlobalStateLens = lens snapRestoreIncludeGlobalState (\x y -> x {snapRestoreIncludeGlobalState = y})
+snapshotRestoreSettingsIncludeGlobalStateLens :: Lens' SnapshotRestoreSettings Bool
+snapshotRestoreSettingsIncludeGlobalStateLens = lens snapRestoreIncludeGlobalState (\x y -> x {snapRestoreIncludeGlobalState = y})
 
-snapRestoreRenamePatternLens :: Lens' SnapshotRestoreSettings (Maybe RestoreRenamePattern)
-snapRestoreRenamePatternLens = lens snapRestoreRenamePattern (\x y -> x {snapRestoreRenamePattern = y})
+snapshotRestoreSettingsRenamePatternLens :: Lens' SnapshotRestoreSettings (Maybe RestoreRenamePattern)
+snapshotRestoreSettingsRenamePatternLens = lens snapRestoreRenamePattern (\x y -> x {snapRestoreRenamePattern = y})
 
-snapRestoreRenameReplacementLens :: Lens' SnapshotRestoreSettings (Maybe (NonEmpty RestoreRenameToken))
-snapRestoreRenameReplacementLens = lens snapRestoreRenameReplacement (\x y -> x {snapRestoreRenameReplacement = y})
+snapshotRestoreSettingsRenameReplacementLens :: Lens' SnapshotRestoreSettings (Maybe (NonEmpty RestoreRenameToken))
+snapshotRestoreSettingsRenameReplacementLens = lens snapRestoreRenameReplacement (\x y -> x {snapRestoreRenameReplacement = y})
 
-snapRestorePartialLens :: Lens' SnapshotRestoreSettings Bool
-snapRestorePartialLens = lens snapRestorePartial (\x y -> x {snapRestorePartial = y})
+snapshotRestoreSettingsPartialLens :: Lens' SnapshotRestoreSettings Bool
+snapshotRestoreSettingsPartialLens = lens snapRestorePartial (\x y -> x {snapRestorePartial = y})
 
-snapRestoreIncludeAliasesLens :: Lens' SnapshotRestoreSettings Bool
-snapRestoreIncludeAliasesLens = lens snapRestoreIncludeAliases (\x y -> x {snapRestoreIncludeAliases = y})
+snapshotRestoreSettingsIncludeAliasesLens :: Lens' SnapshotRestoreSettings Bool
+snapshotRestoreSettingsIncludeAliasesLens = lens snapRestoreIncludeAliases (\x y -> x {snapRestoreIncludeAliases = y})
 
-snapRestoreIndexSettingsOverridesLens :: Lens' SnapshotRestoreSettings (Maybe RestoreIndexSettings)
-snapRestoreIndexSettingsOverridesLens = lens snapRestoreIndexSettingsOverrides (\x y -> x {snapRestoreIndexSettingsOverrides = y})
+snapshotRestoreSettingsIndexSettingsOverridesLens :: Lens' SnapshotRestoreSettings (Maybe RestoreIndexSettings)
+snapshotRestoreSettingsIndexSettingsOverridesLens = lens snapRestoreIndexSettingsOverrides (\x y -> x {snapRestoreIndexSettingsOverrides = y})
 
-snapRestoreIgnoreIndexSettingsLens :: Lens' SnapshotRestoreSettings (Maybe (NonEmpty Text))
-snapRestoreIgnoreIndexSettingsLens = lens snapRestoreIgnoreIndexSettings (\x y -> x {snapRestoreIgnoreIndexSettings = y})
+snapshotRestoreSettingsIgnoreIndexSettingsLens :: Lens' SnapshotRestoreSettings (Maybe (NonEmpty Text))
+snapshotRestoreSettingsIgnoreIndexSettingsLens = lens snapRestoreIgnoreIndexSettings (\x y -> x {snapRestoreIgnoreIndexSettings = y})
 
 newtype SnapshotRepoUpdateSettings = SnapshotRepoUpdateSettings
   { -- | After creation/update, synchronously check that nodes can
@@ -295,8 +295,8 @@
   }
   deriving stock (Eq, Show)
 
-repoUpdateVerifyLens :: Lens' SnapshotRepoUpdateSettings Bool
-repoUpdateVerifyLens = lens repoUpdateVerify (\x y -> x {repoUpdateVerify = y})
+snapshotRepoUpdateSettingsUpdateVerifyLens :: Lens' SnapshotRepoUpdateSettings Bool
+snapshotRepoUpdateSettingsUpdateVerifyLens = lens repoUpdateVerify (\x y -> x {repoUpdateVerify = y})
 
 -- | Reasonable defaults for repo creation/update
 --
@@ -354,23 +354,23 @@
               .:? "max_snapshot_bytes_per_sec"
     | otherwise = Left (RepoTypeMismatch fsRepoType gSnapshotRepoType)
 
-fsrNameLens :: Lens' FsSnapshotRepo SnapshotRepoName
-fsrNameLens = lens fsrName (\x y -> x {fsrName = y})
+fsSnapshotRepoNameLens :: Lens' FsSnapshotRepo SnapshotRepoName
+fsSnapshotRepoNameLens = lens fsrName (\x y -> x {fsrName = y})
 
-fsrLocationLens :: Lens' FsSnapshotRepo FilePath
-fsrLocationLens = lens fsrLocation (\x y -> x {fsrLocation = y})
+fsSnapshotRepoLocationLens :: Lens' FsSnapshotRepo FilePath
+fsSnapshotRepoLocationLens = lens fsrLocation (\x y -> x {fsrLocation = y})
 
-fsrCompressMetadataLens :: Lens' FsSnapshotRepo Bool
-fsrCompressMetadataLens = lens fsrCompressMetadata (\x y -> x {fsrCompressMetadata = y})
+fsSnapshotRepoCompressMetadataLens :: Lens' FsSnapshotRepo Bool
+fsSnapshotRepoCompressMetadataLens = lens fsrCompressMetadata (\x y -> x {fsrCompressMetadata = y})
 
-fsrChunkSizeLens :: Lens' FsSnapshotRepo (Maybe Bytes)
-fsrChunkSizeLens = lens fsrChunkSize (\x y -> x {fsrChunkSize = y})
+fsSnapshotRepoChunkSizeLens :: Lens' FsSnapshotRepo (Maybe Bytes)
+fsSnapshotRepoChunkSizeLens = lens fsrChunkSize (\x y -> x {fsrChunkSize = y})
 
-fsrMaxRestoreBytesPerSecLens :: Lens' FsSnapshotRepo (Maybe Bytes)
-fsrMaxRestoreBytesPerSecLens = lens fsrMaxRestoreBytesPerSec (\x y -> x {fsrMaxRestoreBytesPerSec = y})
+fsSnapshotRepoMaxRestoreBytesPerSecLens :: Lens' FsSnapshotRepo (Maybe Bytes)
+fsSnapshotRepoMaxRestoreBytesPerSecLens = lens fsrMaxRestoreBytesPerSec (\x y -> x {fsrMaxRestoreBytesPerSec = y})
 
-fsrMaxSnapshotBytesPerSecLens :: Lens' FsSnapshotRepo (Maybe Bytes)
-fsrMaxSnapshotBytesPerSecLens = lens fsrMaxSnapshotBytesPerSec (\x y -> x {fsrMaxSnapshotBytesPerSec = y})
+fsSnapshotRepoMaxSnapshotBytesPerSecLens :: Lens' FsSnapshotRepo (Maybe Bytes)
+fsSnapshotRepoMaxSnapshotBytesPerSecLens = lens fsrMaxSnapshotBytesPerSec (\x y -> x {fsrMaxSnapshotBytesPerSec = y})
 
 parseRepo :: Parser a -> Either SnapshotRepoConversionError a
 parseRepo parser = case parseEither (const parser) () of
@@ -413,20 +413,20 @@
   }
   deriving stock (Eq, Show)
 
-snapWaitForCompletionLens :: Lens' SnapshotCreateSettings Bool
-snapWaitForCompletionLens = lens snapWaitForCompletion (\x y -> x {snapWaitForCompletion = y})
+snapshotCreateSettingsWaitForCompletionLens :: Lens' SnapshotCreateSettings Bool
+snapshotCreateSettingsWaitForCompletionLens = lens snapWaitForCompletion (\x y -> x {snapWaitForCompletion = y})
 
-snapIndicesLens :: Lens' SnapshotCreateSettings (Maybe IndexSelection)
-snapIndicesLens = lens snapIndices (\x y -> x {snapIndices = y})
+snapshotCreateSettingsIndicesLens :: Lens' SnapshotCreateSettings (Maybe IndexSelection)
+snapshotCreateSettingsIndicesLens = lens snapIndices (\x y -> x {snapIndices = y})
 
-snapIgnoreUnavailableLens :: Lens' SnapshotCreateSettings Bool
-snapIgnoreUnavailableLens = lens snapIgnoreUnavailable (\x y -> x {snapIgnoreUnavailable = y})
+snapshotCreateSettingsIgnoreUnavailableLens :: Lens' SnapshotCreateSettings Bool
+snapshotCreateSettingsIgnoreUnavailableLens = lens snapIgnoreUnavailable (\x y -> x {snapIgnoreUnavailable = y})
 
-snapIncludeGlobalStateLens :: Lens' SnapshotCreateSettings Bool
-snapIncludeGlobalStateLens = lens snapIncludeGlobalState (\x y -> x {snapIncludeGlobalState = y})
+snapshotCreateSettingsIncludeGlobalStateLens :: Lens' SnapshotCreateSettings Bool
+snapshotCreateSettingsIncludeGlobalStateLens = lens snapIncludeGlobalState (\x y -> x {snapIncludeGlobalState = y})
 
-snapPartialLens :: Lens' SnapshotCreateSettings Bool
-snapPartialLens = lens snapPartial (\x y -> x {snapPartial = y})
+snapshotCreateSettingsPartialLens :: Lens' SnapshotCreateSettings Bool
+snapshotCreateSettingsPartialLens = lens snapPartial (\x y -> x {snapPartial = y})
 
 -- | Reasonable defaults for snapshot creation
 --
@@ -491,29 +491,29 @@
           <*> o
             .: "snapshot"
 
-snapInfoShardsLens :: Lens' SnapshotInfo ShardResult
-snapInfoShardsLens = lens snapInfoShards (\x y -> x {snapInfoShards = y})
+snapshotInfoShardsLens :: Lens' SnapshotInfo ShardResult
+snapshotInfoShardsLens = lens snapInfoShards (\x y -> x {snapInfoShards = y})
 
-snapInfoFailuresLens :: Lens' SnapshotInfo [SnapshotShardFailure]
-snapInfoFailuresLens = lens snapInfoFailures (\x y -> x {snapInfoFailures = y})
+snapshotInfoFailuresLens :: Lens' SnapshotInfo [SnapshotShardFailure]
+snapshotInfoFailuresLens = lens snapInfoFailures (\x y -> x {snapInfoFailures = y})
 
-snapInfoDurationLens :: Lens' SnapshotInfo NominalDiffTime
-snapInfoDurationLens = lens snapInfoDuration (\x y -> x {snapInfoDuration = y})
+snapshotInfoDurationLens :: Lens' SnapshotInfo NominalDiffTime
+snapshotInfoDurationLens = lens snapInfoDuration (\x y -> x {snapInfoDuration = y})
 
-snapInfoEndTimeLens :: Lens' SnapshotInfo UTCTime
-snapInfoEndTimeLens = lens snapInfoEndTime (\x y -> x {snapInfoEndTime = y})
+snapshotInfoEndTimeLens :: Lens' SnapshotInfo UTCTime
+snapshotInfoEndTimeLens = lens snapInfoEndTime (\x y -> x {snapInfoEndTime = y})
 
-snapInfoStartTimeLens :: Lens' SnapshotInfo UTCTime
-snapInfoStartTimeLens = lens snapInfoStartTime (\x y -> x {snapInfoStartTime = y})
+snapshotInfoStartTimeLens :: Lens' SnapshotInfo UTCTime
+snapshotInfoStartTimeLens = lens snapInfoStartTime (\x y -> x {snapInfoStartTime = y})
 
-snapInfoStateLens :: Lens' SnapshotInfo SnapshotState
-snapInfoStateLens = lens snapInfoState (\x y -> x {snapInfoState = y})
+snapshotInfoStateLens :: Lens' SnapshotInfo SnapshotState
+snapshotInfoStateLens = lens snapInfoState (\x y -> x {snapInfoState = y})
 
-snapInfoIndicesLens :: Lens' SnapshotInfo [IndexName]
-snapInfoIndicesLens = lens snapInfoIndices (\x y -> x {snapInfoIndices = y})
+snapshotInfoIndicesLens :: Lens' SnapshotInfo [IndexName]
+snapshotInfoIndicesLens = lens snapInfoIndices (\x y -> x {snapInfoIndices = y})
 
-snapInfoNameLens :: Lens' SnapshotInfo SnapshotName
-snapInfoNameLens = lens snapInfoName (\x y -> x {snapInfoName = y})
+snapshotInfoNameLens :: Lens' SnapshotInfo SnapshotName
+snapshotInfoNameLens = lens snapInfoName (\x y -> x {snapInfoName = y})
 
 data SnapshotShardFailure = SnapshotShardFailure
   { snapShardFailureIndex :: IndexName,
@@ -537,24 +537,24 @@
           <*> o
             .: "shard_id"
 
-snapShardFailureIndexLens :: Lens' SnapshotShardFailure IndexName
-snapShardFailureIndexLens = lens snapShardFailureIndex (\x y -> x {snapShardFailureIndex = y})
+snapshotShardFailureIndexLens :: Lens' SnapshotShardFailure IndexName
+snapshotShardFailureIndexLens = lens snapShardFailureIndex (\x y -> x {snapShardFailureIndex = y})
 
-snapShardFailureNodeIdLens :: Lens' SnapshotShardFailure (Maybe NodeName)
-snapShardFailureNodeIdLens = lens snapShardFailureNodeId (\x y -> x {snapShardFailureNodeId = y})
+snapshotShardFailureNodeIdLens :: Lens' SnapshotShardFailure (Maybe NodeName)
+snapshotShardFailureNodeIdLens = lens snapShardFailureNodeId (\x y -> x {snapShardFailureNodeId = y})
 
-snapShardFailureReasonLens :: Lens' SnapshotShardFailure Text
-snapShardFailureReasonLens = lens snapShardFailureReason (\x y -> x {snapShardFailureReason = y})
+snapshotShardFailureReasonLens :: Lens' SnapshotShardFailure Text
+snapshotShardFailureReasonLens = lens snapShardFailureReason (\x y -> x {snapShardFailureReason = y})
 
-snapShardFailureShardIdLens :: Lens' SnapshotShardFailure ShardId
-snapShardFailureShardIdLens = lens snapShardFailureShardId (\x y -> x {snapShardFailureShardId = y})
+snapshotShardFailureShardIdLens :: Lens' SnapshotShardFailure ShardId
+snapshotShardFailureShardIdLens = lens snapShardFailureShardId (\x y -> x {snapShardFailureShardId = y})
 
 -- | Regex-stype pattern, e.g. "index_(.+)" to match index names
 newtype RestoreRenamePattern = RestoreRenamePattern {rrPattern :: Text}
   deriving newtype (Eq, Ord, Show, ToJSON)
 
-rrPatternLens :: Lens' RestoreRenamePattern Text
-rrPatternLens = lens rrPattern (\x y -> x {rrPattern = y})
+restoreRenamePatternLens :: Lens' RestoreRenamePattern Text
+restoreRenamePatternLens = lens rrPattern (\x y -> x {rrPattern = y})
 
 -- | A single token in a index renaming scheme for a restore. These
 -- are concatenated into a string before being sent to
@@ -626,5 +626,5 @@
     where
       prs = catMaybes [("index.number_of_replicas" .=) <$> restoreOverrideReplicas]
 
-restoreOverrideReplicasLens :: Lens' RestoreIndexSettings (Maybe ReplicaCount)
-restoreOverrideReplicasLens = lens restoreOverrideReplicas (\x y -> x {restoreOverrideReplicas = y})
+restoreIndexSettingsOverrideReplicasLens :: Lens' RestoreIndexSettings (Maybe ReplicaCount)
+restoreIndexSettingsOverrideReplicasLens = lens restoreOverrideReplicas (\x y -> x {restoreOverrideReplicas = y})
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Sort.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Sort.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Sort.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Sort.hs
@@ -88,23 +88,23 @@
   }
   deriving stock (Eq, Show)
 
-sortFieldNameLens :: Lens' DefaultSort FieldName
-sortFieldNameLens = lens sortFieldName (\x y -> x {sortFieldName = y})
+defaultSortFieldNameLens :: Lens' DefaultSort FieldName
+defaultSortFieldNameLens = lens sortFieldName (\x y -> x {sortFieldName = y})
 
-sortOrderLens :: Lens' DefaultSort SortOrder
-sortOrderLens = lens sortOrder (\x y -> x {sortOrder = y})
+defaultSortOrderLens :: Lens' DefaultSort SortOrder
+defaultSortOrderLens = lens sortOrder (\x y -> x {sortOrder = y})
 
-ignoreUnmappedLens :: Lens' DefaultSort (Maybe Text)
-ignoreUnmappedLens = lens ignoreUnmapped (\x y -> x {ignoreUnmapped = y})
+defaultSortIgnoreUnmappedLens :: Lens' DefaultSort (Maybe Text)
+defaultSortIgnoreUnmappedLens = lens ignoreUnmapped (\x y -> x {ignoreUnmapped = y})
 
-sortModeLens :: Lens' DefaultSort (Maybe SortMode)
-sortModeLens = lens sortMode (\x y -> x {sortMode = y})
+defaultSortSortModeLens :: Lens' DefaultSort (Maybe SortMode)
+defaultSortSortModeLens = lens sortMode (\x y -> x {sortMode = y})
 
-missingSortLens :: Lens' DefaultSort (Maybe Missing)
-missingSortLens = lens missingSort (\x y -> x {missingSort = y})
+defaultSortMissingSortLens :: Lens' DefaultSort (Maybe Missing)
+defaultSortMissingSortLens = lens missingSort (\x y -> x {missingSort = y})
 
-nestedFilterLens :: Lens' DefaultSort (Maybe Filter)
-nestedFilterLens = lens nestedFilter (\x y -> x {nestedFilter = y})
+defaultSortNestedFilterLens :: Lens' DefaultSort (Maybe Filter)
+defaultSortNestedFilterLens = lens nestedFilter (\x y -> x {nestedFilter = y})
 
 -- | 'SortOrder' is 'Ascending' or 'Descending', as you might expect. These get
 --   encoded into "asc" or "desc" when turned into JSON.
diff --git a/src/Database/Bloodhound/Internal/Versions/Common/Types/Suggest.hs b/src/Database/Bloodhound/Internal/Versions/Common/Types/Suggest.hs
--- a/src/Database/Bloodhound/Internal/Versions/Common/Types/Suggest.hs
+++ b/src/Database/Bloodhound/Internal/Versions/Common/Types/Suggest.hs
@@ -47,7 +47,7 @@
 suggestTypeLens = lens suggestType (\x y -> x {suggestType = y})
 
 data SuggestType
-  = SuggestTypePhraseSuggester PhraseSuggester -- TODO GDF
+  = SuggestTypePhraseSuggester PhraseSuggester
   deriving stock (Eq, Show, Generic)
 
 instance ToJSON SuggestType where
@@ -115,6 +115,9 @@
           <*> o .:? "collate"
           <*> o .:? "direct_generator" .!= []
 
+suggestTypePhraseSuggesterLens :: Lens' SuggestType PhraseSuggester
+suggestTypePhraseSuggesterLens = lens (\(SuggestTypePhraseSuggester x) -> x) (const SuggestTypePhraseSuggester)
+
 mkPhraseSuggester :: FieldName -> PhraseSuggester
 mkPhraseSuggester fName =
   PhraseSuggester
@@ -305,11 +308,11 @@
     return $ NamedSuggestionResponse (toText suggestionName') suggestionResponses'
   parseJSON x = typeMismatch "NamedSuggestionResponse" x
 
-nsrNameLens :: Lens' NamedSuggestionResponse Text
-nsrNameLens = lens nsrName (\x y -> x {nsrName = y})
+namedSuggestionResponseNameLens :: Lens' NamedSuggestionResponse Text
+namedSuggestionResponseNameLens = lens nsrName (\x y -> x {nsrName = y})
 
-nsrResponsesLens :: Lens' NamedSuggestionResponse [SuggestResponse]
-nsrResponsesLens = lens nsrResponses (\x y -> x {nsrResponses = y})
+namedSuggestionResponseResponsesLens :: Lens' NamedSuggestionResponse [SuggestResponse]
+namedSuggestionResponseResponsesLens = lens nsrResponses (\x y -> x {nsrResponses = y})
 
 data DirectGeneratorSuggestModeTypes
   = DirectGeneratorSuggestModeMissing
diff --git a/src/Database/Bloodhound/Internal/Versions/ElasticSearch7/Types/PointInTime.hs b/src/Database/Bloodhound/Internal/Versions/ElasticSearch7/Types/PointInTime.hs
--- a/src/Database/Bloodhound/Internal/Versions/ElasticSearch7/Types/PointInTime.hs
+++ b/src/Database/Bloodhound/Internal/Versions/ElasticSearch7/Types/PointInTime.hs
@@ -10,8 +10,8 @@
   }
   deriving stock (Eq, Show)
 
-oPitIdLens :: Lens' OpenPointInTimeResponse Text
-oPitIdLens = lens oPitId (\x y -> x {oPitId = y})
+openPointInTimeIdLens :: Lens' OpenPointInTimeResponse Text
+openPointInTimeIdLens = lens oPitId (\x y -> x {oPitId = y})
 
 instance ToJSON OpenPointInTimeResponse where
   toJSON OpenPointInTimeResponse {..} =
@@ -34,15 +34,15 @@
   parseJSON (Object o) = ClosePointInTime <$> o .: "id"
   parseJSON x = typeMismatch "ClosePointInTime" x
 
+closePointInTimeIdLens :: Lens' ClosePointInTime Text
+closePointInTimeIdLens = lens cPitId (\x y -> x {cPitId = y})
+
 data ClosePointInTimeResponse = ClosePointInTimeResponse
   { succeeded :: Bool,
     numFreed :: Int
   }
   deriving stock (Eq, Show)
 
-cPitIdLens :: Lens' ClosePointInTime Text
-cPitIdLens = lens cPitId (\x y -> x {cPitId = y})
-
 instance ToJSON ClosePointInTimeResponse where
   toJSON ClosePointInTimeResponse {..} =
     object
@@ -57,8 +57,8 @@
     return $ ClosePointInTimeResponse succeeded' numFreed'
   parseJSON x = typeMismatch "ClosePointInTimeResponse" x
 
-succeededLens :: Lens' ClosePointInTimeResponse Bool
-succeededLens = lens succeeded (\x y -> x {succeeded = y})
+closePointInTimeSucceededLens :: Lens' ClosePointInTimeResponse Bool
+closePointInTimeSucceededLens = lens succeeded (\x y -> x {succeeded = y})
 
-numFreedLens :: Lens' ClosePointInTimeResponse Int
-numFreedLens = lens numFreed (\x y -> x {numFreed = y})
+closePointInTimeNumFreedLens :: Lens' ClosePointInTimeResponse Int
+closePointInTimeNumFreedLens = lens numFreed (\x y -> x {numFreed = y})
diff --git a/src/Database/Bloodhound/Internal/Versions/OpenSearch2/Types/PointInTime.hs b/src/Database/Bloodhound/Internal/Versions/OpenSearch2/Types/PointInTime.hs
--- a/src/Database/Bloodhound/Internal/Versions/OpenSearch2/Types/PointInTime.hs
+++ b/src/Database/Bloodhound/Internal/Versions/OpenSearch2/Types/PointInTime.hs
@@ -25,14 +25,14 @@
       <*> o .: "creation_time"
   parseJSON x = typeMismatch "OpenPointInTimeResponse" x
 
-oos2PitIdLens :: Lens' OpenPointInTimeResponse Text
-oos2PitIdLens = lens oos2PitId (\x y -> x {oos2PitId = y})
+openPointInTimeIdLens :: Lens' OpenPointInTimeResponse Text
+openPointInTimeIdLens = lens oos2PitId (\x y -> x {oos2PitId = y})
 
-oos2ShardsLens :: Lens' OpenPointInTimeResponse ShardResult
-oos2ShardsLens = lens oos2Shards (\x y -> x {oos2Shards = y})
+openPointInTimeShardsLens :: Lens' OpenPointInTimeResponse ShardResult
+openPointInTimeShardsLens = lens oos2Shards (\x y -> x {oos2Shards = y})
 
-oos2CreationTimeLens :: Lens' OpenPointInTimeResponse POSIXTime
-oos2CreationTimeLens = lens oos2CreationTime (\x y -> x {oos2CreationTime = y})
+openPointInTimeCreationTimeLens :: Lens' OpenPointInTimeResponse POSIXTime
+openPointInTimeCreationTimeLens = lens oos2CreationTime (\x y -> x {oos2CreationTime = y})
 
 data ClosePointInTime = ClosePointInTime
   { cPitId :: Text
@@ -47,8 +47,8 @@
   parseJSON (Object o) = ClosePointInTime <$> o .: "id"
   parseJSON x = typeMismatch "ClosePointInTime" x
 
-cPitIdLens :: Lens' ClosePointInTime Text
-cPitIdLens = lens cPitId (\x y -> x {cPitId = y})
+closePointInTimeIdLens :: Lens' ClosePointInTime Text
+closePointInTimeIdLens = lens cPitId (\x y -> x {cPitId = y})
 
 data ClosePointInTimeResponse = ClosePointInTimeResponse
   { succeeded :: Bool,
@@ -70,8 +70,8 @@
     return $ ClosePointInTimeResponse succeeded' numFreed'
   parseJSON x = typeMismatch "ClosePointInTimeResponse" x
 
-succeededLens :: Lens' ClosePointInTimeResponse Bool
-succeededLens = lens succeeded (\x y -> x {succeeded = y})
+closePointInTimeSucceededLens :: Lens' ClosePointInTimeResponse Bool
+closePointInTimeSucceededLens = lens succeeded (\x y -> x {succeeded = y})
 
-numFreedLens :: Lens' ClosePointInTimeResponse Int
-numFreedLens = lens numFreed (\x y -> x {numFreed = y})
+closePointInTimeNumFreedLens :: Lens' ClosePointInTimeResponse Int
+closePointInTimeNumFreedLens = lens numFreed (\x y -> x {numFreed = y})
diff --git a/src/Database/Bloodhound/OpenSearch2/Client.hs b/src/Database/Bloodhound/OpenSearch2/Client.hs
--- a/src/Database/Bloodhound/OpenSearch2/Client.hs
+++ b/src/Database/Bloodhound/OpenSearch2/Client.hs
@@ -22,7 +22,7 @@
 import Prelude hiding (filter, head)
 
 -- | 'pitSearch' uses the point in time (PIT) API of elastic, for a given
--- 'IndexName'. Requires Elasticsearch >=7.10. Note that this will consume the
+-- 'IndexName'. Note that this will consume the
 -- entire search result set and will be doing O(n) list appends so this may
 -- not be suitable for large result sets. In that case, the point in time API
 -- should be used directly with `openPointInTime` and `closePointInTime`.
@@ -33,7 +33,12 @@
 --
 -- For more information see
 -- <https://opensearch.org/docs/latest/search-plugins/point-in-time/>.
-pitSearch :: forall a m. (FromJSON a, MonadBH m) => IndexName -> Search -> m [Hit a]
+pitSearch ::
+  forall a m.
+  (FromJSON a, MonadBH m, WithBackend OpenSearch2 m) =>
+  IndexName ->
+  Search ->
+  m [Hit a]
 pitSearch indexName search = do
   openResp <- openPointInTime indexName
   case openResp of
@@ -75,7 +80,7 @@
 -- For more information see
 -- <https://opensearch.org/docs/latest/search-plugins/point-in-time/>.
 openPointInTime ::
-  (MonadBH m) =>
+  (MonadBH m, WithBackend OpenSearch2 m) =>
   IndexName ->
   m (ParsedEsResponse OpenPointInTimeResponse)
 openPointInTime indexName = performBHRequest $ Requests.openPointInTime indexName
@@ -85,7 +90,7 @@
 -- For more information see
 -- <https://opensearch.org/docs/latest/search-plugins/point-in-time/>.
 closePointInTime ::
-  (MonadBH m) =>
+  (MonadBH m, WithBackend OpenSearch2 m) =>
   ClosePointInTime ->
   m (ParsedEsResponse ClosePointInTimeResponse)
 closePointInTime q = performBHRequest $ Requests.closePointInTime q
