@@ -0,0 +1,525 @@
1+module Yoga.Elasticsearch.Elasticsearch where
5+import Data.Maybe (Maybe(..))
6+import Data.Newtype (class Newtype)
7+import Data.Nullable (Nullable)
8+import Data.Nullable as Nullable
9+import Data.Time.Duration (Milliseconds)
10+import Effect (Effect)
11+import Effect.Aff (Aff)
12+import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4)
13+import Foreign (Foreign)
14+import Prim.Row (class Union)
15+import Promise (Promise)
16+import Promise.Aff (toAffE) as Promise
18+-- Opaque Elasticsearch types
19+foreign import data Client :: Type
21+-- Newtypes for type safety
23+-- Connection configuration
24+newtype Node = Node String
25+derive instance Newtype Node _
26+derive newtype instance Eq Node
27+derive newtype instance Show Node
29+newtype ApiKeyId = ApiKeyId String
30+derive instance Newtype ApiKeyId _
31+derive newtype instance Eq ApiKeyId
32+derive newtype instance Show ApiKeyId
34+newtype ApiKeySecret = ApiKeySecret String
35+derive instance Newtype ApiKeySecret _
36+derive newtype instance Eq ApiKeySecret
37+derive newtype instance Show ApiKeySecret
39+newtype Username = Username String
40+derive instance Newtype Username _
41+derive newtype instance Eq Username
42+derive newtype instance Show Username
44+newtype Password = Password String
45+derive instance Newtype Password _
46+derive newtype instance Eq Password
47+derive newtype instance Show Password
49+newtype BearerToken = BearerToken String
50+derive instance Newtype BearerToken _
51+derive newtype instance Eq BearerToken
52+derive newtype instance Show BearerToken
54+newtype CloudId = CloudId String
55+derive instance Newtype CloudId _
56+derive newtype instance Eq CloudId
57+derive newtype instance Show CloudId
59+newtype RequestTimeout = RequestTimeout Milliseconds
60+derive instance Newtype RequestTimeout _
61+derive newtype instance Eq RequestTimeout
62+derive newtype instance Ord RequestTimeout
63+derive newtype instance Show RequestTimeout
65+newtype MaxRetries = MaxRetries Int
66+derive instance Newtype MaxRetries _
67+derive newtype instance Eq MaxRetries
68+derive newtype instance Ord MaxRetries
69+derive newtype instance Show MaxRetries
71+-- Index and document types
72+newtype IndexName = IndexName String
73+derive instance Newtype IndexName _
74+derive newtype instance Eq IndexName
75+derive newtype instance Show IndexName
77+newtype DocumentId = DocumentId String
78+derive instance Newtype DocumentId _
79+derive newtype instance Eq DocumentId
80+derive newtype instance Show DocumentId
82+newtype Routing = Routing String
83+derive instance Newtype Routing _
84+derive newtype instance Eq Routing
85+derive newtype instance Show Routing
87+newtype RefreshPolicy = RefreshPolicy String
88+derive instance Newtype RefreshPolicy _
89+derive newtype instance Eq RefreshPolicy
90+derive newtype instance Show RefreshPolicy
92+-- Convenience refresh policy constructors
93+refreshTrue :: RefreshPolicy
94+refreshTrue = RefreshPolicy "true"
96+refreshFalse :: RefreshPolicy
97+refreshFalse = RefreshPolicy "false"
99+refreshWaitFor :: RefreshPolicy
100+refreshWaitFor = RefreshPolicy "wait_for"
103+newtype ScrollId = ScrollId String
104+derive instance Newtype ScrollId _
105+derive newtype instance Eq ScrollId
106+derive newtype instance Show ScrollId
108+newtype ScrollTimeout = ScrollTimeout String
109+derive instance Newtype ScrollTimeout _
110+derive newtype instance Eq ScrollTimeout
111+derive newtype instance Show ScrollTimeout
114+newtype ClusterName = ClusterName String
115+derive instance Newtype ClusterName _
116+derive newtype instance Eq ClusterName
117+derive newtype instance Show ClusterName
119+newtype ClusterUUID = ClusterUUID String
120+derive instance Newtype ClusterUUID _
121+derive newtype instance Eq ClusterUUID
122+derive newtype instance Show ClusterUUID
124+newtype Version = Version String
125+derive instance Newtype Version _
126+derive newtype instance Eq Version
127+derive newtype instance Show Version
129+newtype BuildHash = BuildHash String
130+derive instance Newtype BuildHash _
131+derive newtype instance Eq BuildHash
132+derive newtype instance Show BuildHash
134+-- Document and query types
135+newtype Document = Document Foreign
136+derive instance Newtype Document _
138+newtype Query = Query Foreign
139+derive instance Newtype Query _
141+newtype Script = Script Foreign
142+derive instance Newtype Script _
144+newtype Mappings = Mappings Foreign
145+derive instance Newtype Mappings _
147+newtype Settings = Settings Foreign
148+derive instance Newtype Settings _
150+newtype Sort = Sort Foreign
151+derive instance Newtype Sort _
153+-- Document metadata types
154+newtype DocumentVersion = DocumentVersion Int
155+derive instance Newtype DocumentVersion _
156+derive newtype instance Eq DocumentVersion
157+derive newtype instance Ord DocumentVersion
158+derive newtype instance Show DocumentVersion
160+newtype SequenceNumber = SequenceNumber Int
161+derive instance Newtype SequenceNumber _
162+derive newtype instance Eq SequenceNumber
163+derive newtype instance Ord SequenceNumber
164+derive newtype instance Show SequenceNumber
166+newtype PrimaryTerm = PrimaryTerm Int
167+derive instance Newtype PrimaryTerm _
168+derive newtype instance Eq PrimaryTerm
169+derive newtype instance Ord PrimaryTerm
170+derive newtype instance Show PrimaryTerm
172+newtype IndexResult = IndexResult String
173+derive instance Newtype IndexResult _
174+derive newtype instance Eq IndexResult
175+derive newtype instance Show IndexResult
178+newtype ShardCount = ShardCount Int
179+derive instance Newtype ShardCount _
180+derive newtype instance Eq ShardCount
181+derive newtype instance Ord ShardCount
182+derive newtype instance Show ShardCount
185+ { total :: ShardCount
186+ , successful :: ShardCount
187+ , failed :: ShardCount
190+-- Search result types
191+newtype Score = Score Number
192+derive instance Newtype Score _
193+derive newtype instance Eq Score
194+derive newtype instance Ord Score
195+derive newtype instance Show Score
197+newtype TookMilliseconds = TookMilliseconds Int
198+derive instance Newtype TookMilliseconds _
199+derive newtype instance Eq TookMilliseconds
200+derive newtype instance Ord TookMilliseconds
201+derive newtype instance Show TookMilliseconds
203+newtype HitCount = HitCount Int
204+derive instance Newtype HitCount _
205+derive newtype instance Eq HitCount
206+derive newtype instance Ord HitCount
207+derive newtype instance Show HitCount
209+newtype SkippedCount = SkippedCount Int
210+derive instance Newtype SkippedCount _
211+derive newtype instance Eq SkippedCount
212+derive newtype instance Ord SkippedCount
213+derive newtype instance Show SkippedCount
215+-- Operation configuration types
216+newtype RetryCount = RetryCount Int
217+derive instance Newtype RetryCount _
218+derive newtype instance Eq RetryCount
219+derive newtype instance Ord RetryCount
220+derive newtype instance Show RetryCount
222+newtype FromOffset = FromOffset Int
223+derive instance Newtype FromOffset _
224+derive newtype instance Eq FromOffset
225+derive newtype instance Ord FromOffset
226+derive newtype instance Show FromOffset
228+newtype ResultSize = ResultSize Int
229+derive instance Newtype ResultSize _
230+derive newtype instance Eq ResultSize
231+derive newtype instance Ord ResultSize
232+derive newtype instance Show ResultSize
234+-- Authentication configuration
237+ , api_key :: ApiKeySecret
241+ { username :: Username
242+ , password :: Password
245+-- Client configuration
246+type ClientConfigImpl =
248+ , nodes :: Array Node
249+ , cloud :: { id :: CloudId }
250+ , auth :: { apiKey :: ApiKeyAuth }
251+ , basicAuth :: BasicAuth
252+ , bearerToken :: BearerToken
253+ , requestTimeout :: RequestTimeout
254+ , maxRetries :: MaxRetries
255+ , compression :: Boolean
256+ , ssl :: { rejectUnauthorized :: Boolean }
259+foreign import createClientImpl :: forall opts. EffectFn1 { | opts } Client
261+createClient :: forall opts opts_. Union opts opts_ ClientConfigImpl => { | opts } -> Effect Client
262+createClient opts = runEffectFn1 createClientImpl opts
266+ { name :: ClusterName
267+ , cluster_name :: ClusterName
268+ , cluster_uuid :: ClusterUUID
271+ , build_flavor :: String
272+ , build_type :: String
273+ , build_hash :: BuildHash
274+ , build_date :: String
275+ , build_snapshot :: Boolean
276+ , lucene_version :: Version
277+ , minimum_wire_compatibility_version :: Version
278+ , minimum_index_compatibility_version :: Version
283+foreign import infoImpl :: EffectFn1 Client (Promise ClusterInfo)
285+info :: Client -> Aff ClusterInfo
286+info = runEffectFn1 infoImpl >>> Promise.toAffE
289+foreign import pingImpl :: EffectFn1 Client (Promise Boolean)
291+ping :: Client -> Aff Boolean
292+ping = runEffectFn1 pingImpl >>> Promise.toAffE
297+type CreateIndexOptionsImpl =
298+ ( mappings :: Mappings
299+ , settings :: Settings
302+type CreateIndexResponse =
303+ { acknowledged :: Boolean
304+ , shards_acknowledged :: Boolean
305+ , index :: IndexName
308+foreign import createIndexImpl :: forall opts. EffectFn3 Client IndexName { | opts } (Promise CreateIndexResponse)
310+createIndex :: forall opts opts_. Union opts opts_ CreateIndexOptionsImpl => IndexName -> { | opts } -> Client -> Aff CreateIndexResponse
311+createIndex index opts client = runEffectFn3 createIndexImpl client index opts # Promise.toAffE
314+type DeleteIndexResponse =
315+ { acknowledged :: Boolean
318+foreign import deleteIndexImpl :: EffectFn2 Client IndexName (Promise DeleteIndexResponse)
320+deleteIndex :: IndexName -> Client -> Aff DeleteIndexResponse
321+deleteIndex index client = runEffectFn2 deleteIndexImpl client index # Promise.toAffE
323+-- Check if index exists
324+foreign import indexExistsImpl :: EffectFn2 Client IndexName (Promise Boolean)
326+indexExists :: IndexName -> Client -> Aff Boolean
327+indexExists index client = runEffectFn2 indexExistsImpl client index # Promise.toAffE
329+-- Document operations
332+type IndexDocumentOptionsImpl =
334+ , routing :: Routing
335+ , refresh :: RefreshPolicy
336+ , timeout :: RequestTimeout
339+type IndexDocumentResponse =
340+ { _index :: IndexName
342+ , _version :: DocumentVersion
343+ , result :: IndexResult
344+ , _shards :: ShardInfo
347+foreign import indexDocumentImpl :: forall opts. EffectFn4 Client IndexName Document { | opts } (Promise IndexDocumentResponse)
349+indexDocument :: forall opts opts_. Union opts opts_ IndexDocumentOptionsImpl => IndexName -> Document -> { | opts } -> Client -> Aff IndexDocumentResponse
350+indexDocument index doc opts client = runEffectFn4 indexDocumentImpl client index doc opts # Promise.toAffE
353+type GetDocumentOptionsImpl =
354+ ( routing :: Routing
355+ , _source :: Boolean
356+ , _source_includes :: Array String
357+ , _source_excludes :: Array String
360+type GetDocumentResponse =
361+ { _index :: IndexName
363+ , _version :: DocumentVersion
364+ , _seq_no :: SequenceNumber
365+ , _primary_term :: PrimaryTerm
367+ , _source :: Nullable Foreign
370+foreign import getDocumentImpl :: forall opts. EffectFn4 Client IndexName DocumentId { | opts } (Promise GetDocumentResponse)
372+getDocument :: forall opts opts_. Union opts opts_ GetDocumentOptionsImpl => IndexName -> DocumentId -> { | opts } -> Client -> Aff GetDocumentResponse
373+getDocument index docId opts client = runEffectFn4 getDocumentImpl client index docId opts # Promise.toAffE
375+-- Get document simple (returns Maybe)
376+getDocumentMaybe :: IndexName -> DocumentId -> Client -> Aff (Maybe Foreign)
377+getDocumentMaybe index docId client = do
378+ result <- getDocument index docId {} client
379+ pure $ if result.found
380+ then Nullable.toMaybe result._source
384+type UpdateDocumentOptionsImpl =
387+ , routing :: Routing
388+ , refresh :: RefreshPolicy
389+ , retry_on_conflict :: RetryCount
392+type UpdateDocumentResponse =
393+ { _index :: IndexName
395+ , _version :: DocumentVersion
396+ , result :: IndexResult
399+foreign import updateDocumentImpl :: forall opts. EffectFn4 Client IndexName DocumentId { | opts } (Promise UpdateDocumentResponse)
401+updateDocument :: forall opts opts_. Union opts opts_ UpdateDocumentOptionsImpl => IndexName -> DocumentId -> { | opts } -> Client -> Aff UpdateDocumentResponse
402+updateDocument index docId opts client = runEffectFn4 updateDocumentImpl client index docId opts # Promise.toAffE
405+type DeleteDocumentOptionsImpl =
406+ ( routing :: Routing
407+ , refresh :: RefreshPolicy
410+type DeleteDocumentResponse =
411+ { _index :: IndexName
413+ , _version :: DocumentVersion
414+ , result :: IndexResult
417+foreign import deleteDocumentImpl :: forall opts. EffectFn4 Client IndexName DocumentId { | opts } (Promise DeleteDocumentResponse)
419+deleteDocument :: forall opts opts_. Union opts opts_ DeleteDocumentOptionsImpl => IndexName -> DocumentId -> { | opts } -> Client -> Aff DeleteDocumentResponse
420+deleteDocument index docId opts client = runEffectFn4 deleteDocumentImpl client index docId opts # Promise.toAffE
424+type SearchOptionsImpl =
426+ , from :: FromOffset
427+ , size :: ResultSize
429+ , _source :: Boolean
430+ , _source_includes :: Array String
431+ , _source_excludes :: Array String
432+ , track_total_hits :: Boolean
433+ , scroll :: ScrollTimeout
434+ , routing :: Routing
438+ { _index :: IndexName
440+ , _score :: Nullable Score
441+ , _source :: Foreign
444+type SearchResponse =
445+ { took :: TookMilliseconds
446+ , timed_out :: Boolean
448+ { total :: ShardCount
449+ , successful :: ShardCount
450+ , skipped :: SkippedCount
451+ , failed :: ShardCount
454+ { total :: { value :: HitCount, relation :: String }
455+ , max_score :: Nullable Score
456+ , hits :: Array SearchHit
458+ , _scroll_id :: Nullable ScrollId
461+foreign import searchImpl :: forall opts. EffectFn3 Client (Nullable IndexName) { | opts } (Promise SearchResponse)
463+search :: forall opts opts_. Union opts opts_ SearchOptionsImpl => Maybe IndexName -> { | opts } -> Client -> Aff SearchResponse
464+search index opts client = runEffectFn3 searchImpl client (Nullable.toNullable index) opts # Promise.toAffE
466+-- Search all indices
467+searchAll :: forall opts opts_. Union opts opts_ SearchOptionsImpl => { | opts } -> Client -> Aff SearchResponse
468+searchAll opts client = search Nothing opts client
470+-- Scroll API for pagination
471+type ScrollOptionsImpl =
472+ ( scroll :: ScrollTimeout
475+foreign import scrollImpl :: forall opts. EffectFn3 Client ScrollId { | opts } (Promise SearchResponse)
477+scroll :: forall opts opts_. Union opts opts_ ScrollOptionsImpl => ScrollId -> { | opts } -> Client -> Aff SearchResponse
478+scroll scrollId opts client = runEffectFn3 scrollImpl client scrollId opts # Promise.toAffE
481+foreign import clearScrollImpl :: EffectFn2 Client ScrollId (Promise { succeeded :: Boolean })
483+clearScroll :: ScrollId -> Client -> Aff { succeeded :: Boolean }
484+clearScroll scrollId client = runEffectFn2 clearScrollImpl client scrollId # Promise.toAffE
488+type BulkOperation = Foreign
491+ { took :: TookMilliseconds
493+ , items :: Array Foreign
496+foreign import bulkImpl :: EffectFn2 Client (Array BulkOperation) (Promise BulkResponse)
498+bulk :: Array BulkOperation -> Client -> Aff BulkResponse
499+bulk operations client = runEffectFn2 bulkImpl client operations # Promise.toAffE
502+type CountOptionsImpl =
510+foreign import countImpl :: forall opts. EffectFn3 Client (Nullable IndexName) { | opts } (Promise CountResponse)
512+count :: forall opts opts_. Union opts opts_ CountOptionsImpl => Maybe IndexName -> { | opts } -> Client -> Aff CountResponse
513+count index opts client = runEffectFn3 countImpl client (Nullable.toNullable index) opts # Promise.toAffE
516+foreign import refreshImpl :: EffectFn2 Client IndexName (Promise { _shards :: ShardInfo })
518+refresh :: IndexName -> Client -> Aff { _shards :: ShardInfo }
519+refresh index client = runEffectFn2 refreshImpl client index # Promise.toAffE
522+foreign import closeImpl :: EffectFn1 Client (Promise Unit)
524+close :: Client -> Aff Unit
525+close = runEffectFn1 closeImpl >>> Promise.toAffE