Swiftpack.co - Package - pksprojects/ElasticSwift

ElasticSwift

Build Status codecov

Project Status

This project is actively in developement, more information will be made available as project progresses.

If you'd like to contribute pull requests are welcome.

  • Platform support for macOS, iOS & linux.

  • Query DSL builders and helpers similar to elasticsearch Java client. Check the table below to see full list of avaiable QueryBuilders

Project Goal

Our goal is to make a very Swifty and high-performant elasticsearch client.

High-performant means providing end user's response under 100ms not including the time elasticsearch took to process the request.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

CocoaPods 1.6.0+ is required to build ElasticSwift.

To integrate Elasticswift into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'ElasticSwift', '~> 1.0.0-alpha.9'
    pod 'ElasticSwiftCore', '~> 1.0.0-alpha.9'
    pod 'ElasticSwiftQueryDSL', '~> 1.0.0-alpha.9'
    pod 'ElasticSwiftCodableUtils', '~> 1.0.0-alpha.9'
    pod 'ElasticSwiftNetworking', '~> 1.0.0-alpha.9'
end

Then, run the following command:

$ pod install

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler. It is in early development, but ElasticSwift does support its use on supported platforms.

Once you have your Swift package set up, adding ElasticSwift as a dependency is as easy as adding it to the dependencies value of your Package.swift.

dependencies: [
    .package(url: "https://github.com/pksprojects/ElasticSwift.git", from: "1.0.0-alpha.9")
]

Usage

Client

Creating ElasticClient.

import ElasticSwift

var settings = Settings.default // Creates default settings for client
var client = ElasticClient(settings: settings) // Creates client with specified settings

var client = ElasticClient() // Creates client with default settings

Creating Settings for specified host.


// with host address as string
var settings = Settings.default(forHost: "http://samplehost:port")

// with host address
var host = Host(string: "http://samplehost:port")
var settings = Settings(forHost: host, adaptorConfig: HTTPClientAdaptorConfiguration.default)


let cred = BasicClientCredential(username: "elastic", password: "elastic")
let certPath = "/path/to/certificate.der"
let sslConfig = SSLConfiguration(certPath: certPath, isSelf: true)
let adaptorConfig = URLSessionAdaptorConfiguration(sslConfig: sslConfig)
let settings = Settings(forHosts: ["https://samplehost:port"], withCredentials: cred, adaptorConfig: adaptorConfig)
let client = RestClient(settings: settings)

When creating default settings it creates settings for http://localhost:9200.

Index

Create and Delete Index

func createHandler(_ result: Result<CreateIndexResponse, Error>) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

// creating index
let createIndexRequest = CreateIndexRequest(name: "indexName")
client.indices.create(createIndexRequest, completionHandler: createHandler) // executes request

// delete index
func deleteHandler(_ response: DeleteIndexResponse?, _ error: Error?) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

let deleteIndexRequest = DeleteIndexRequest(name: "indexName")
client.indices.delete(deleteIndexRequest, completionHandler: deleteHandler) // executes request

Document

Document CRUD

class MyClass: Codable {
  var myField: String?
}

// index document
func indexHandler(_ result: Result<IndexResponse, Error>) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

let mySource = MyClass()
mySource.myField = "My value"

let indexRequest = try IndexRequestBuilder<MyClass>() { builder in
            _ = builder.set(index: "indexName")
                .set(type: "type")
                .set(id: "id")
                .set(source: mySource)
        }
        .build()

client.index(indexRequest, completionHandler: indexHandler)

// get document
func getHandler(_ result: Result<GetResponse<MyClass>, Error>) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

let getRequest = GetRequestBuilder<MyClass>() { builder in
            builder.set(id: "id")
                .set(index: "indexName")
                .set(type: "type")
        }
        .build()

client.get(getRequest, completionHandler: getHandler)

// delete document
func deleteHandler(_ result: Result<DeleteResponse, Error>) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

let deleteRequest = try DeleteRequestBuilder() { builder in
        builder.set(index: "indexName")
                .set(type: "type")
                .set(id: "id")
    } .build()

client.delete(deleteRequest, completionHandler: deleteHandler)

Query

Currently not all QueryBuilders are available. Future releases will add support for additional QueryBuilders. Check below for details


let builder = QueryBuilders.boolQuery()
let mustMatch = QueryBuilders.matchQuery().match(field: "fieldName", value: "value")
let mustNotMatch = QueryBuilders.matchQuery().match(field: "fieldName", value: "value")
builder.must(query: mustMatch)
builder.mustNot(query: mustNotMatch)

Search

Creating simple search request.


func handler(_ result: Result<SearchResponse<Message>, Error>) -> Void {
    switch result {
        case .failure(let error):
            print("Error", error)
        case .success(let response):
            print("Response", response)
    }
}

let queryBuilder = QueryBuilders.boolQuery()
let match = QueryBuilders.matchQuery().match(field: "myField", value: "MySearchValue")
queryBuilder.must(query: match)

let sort =  SortBuilders.fieldSort("msg") // use "msg.keyword" as field name in case of text field
    .set(order: .asc)
    .build()

let request = try SearchRequestBuilder() { builder in
            builder.set(indices: "indexName")
                .set(types: "type")
                .set(query: queryBuilder.query)
                .set(sort: sort)
        } .build()

client.search(request, completionHandler: handler)

QueryDSL

Below Table lists all the available search queries with their corresponding QueryBuilder class name and helper method name in the QueryBuilders utility class.

| Search Query | QueryBuilder Class | Method in QueryBuilders | | :--- | :--- | :--- | | ConstantScoreQuery | ConstantScoreQueryBuilder | QueryBuilders.constantScoreQuery() | | BoolQuery | BoolQueryBuilder | QueryBuilders.boolQuery() | | DisMaxQuery | DisMaxQueryBuilder | QueryBuilders.disMaxQuery() | | FunctionScoreQuery | FunctionScoreQueryBuilder | QueryBuilders.functionScoreQuery() | | BoostingQuery | BoostingQueryBuilder | QueryBuilders.boostingeQuery() | | MatchQuery | MatchQueryBuilder | QueryBuilders.matchQuery() | | MatchPhraseQuery | MatchPhraseQueryBuilder | QueryBuilders.matchPhraseQuery() | | MatchPhrasePrefixQuery | MatchPhrasePrefixQueryBuilder | QueryBuilders.matchPhrasePrefixQuery() | | MultiMatchQuery | MultiMatchQueryBuilder | QueryBuilders.multiMatchQuery() | | CommonTermsQuery | CommonTermsQueryBuilder | QueryBuilders.commonTermsQuery() | | QueryStringQuery | QueryStringQueryBuilder | QueryBuilders.queryStringQuery() | | SimpleQueryStringQuery | SimpleQueryStringQueryBuilder | QueryBuilders.simpleQueryStringQuery() | | MatchAllQuery | MatchAllQueryBuilder | QueryBuilders.matchAllQuery() | | MatchNoneQuery | MatchNoneQueryBuilder | QueryBuilders.matchNoneQuery() | | TermQuery | TermQueryBuilder | QueryBuilders.termQuery() | | TermsQuery | TermsQueryBuilder | QueryBuilders.termsQuery() | | RangeQuery | RangeQueryBuilder | QueryBuilders.rangeQuery() | | ExistsQuery | ExistsQueryBuilder | QueryBuilders.existsQuery() | | PrefixQuery | PrefixQueryBuilder | QueryBuilders.prefixQuery() | | WildCardQuery | WildCardQueryBuilder | QueryBuilders.wildCardQuery() | | RegexpQuery | RegexpQueryBuilder | QueryBuilders.regexpQuery() | | FuzzyQuery | FuzzyQueryBuilder | QueryBuilders.fuzzyQuery() | | TypeQuery | TypeQueryBuilder | QueryBuilders.typeQuery() | | IdsQuery | IdsQueryBuilder | QueryBuilders.idsQuery() |

Github

link
Stars: 21
Help us keep the lights on

Releases

v1.0.0-alpha.9 - Aug 1, 2019

ChangeLog

  • (#31) UpdateRequest support.
  • (#33) UpdateByQueryRequest support.
  • (#32) DeleteByQyeryRequest support.
  • (#40 ) Split Lib into following modules:- ElasticSwiftCore -> Core module with common/shared protocols, class, struct, enum. ElasticSwiftQueryDSL -> Query and QueryBuilders. ElasticSwiftNetworking -> Networking layer of the lib. ElasticSwiftCodableUtils -> CodableUtils ElasticSwift -> main lib depends on all other modules.
  • (#44) fix SearchResponse serialization.
  • Ability to initialize DefaultSerializer with custom JSONEncoder &/or JSONDecoder.
  • Improvements to Settings
  • HTTPSettings helper enum.
  • ClientCredential protocol
  • Improved support for plugable clients with HTTPClientAdaptor & ManagedHTTPClientAdaptor protocols
  • fix generic type leakage from response to request.

v1.0.0-alpha.8 - Jul 15, 2019

ChangeLog

  • Support for index aliases, mapping, and setting in CreateIndexRequest.
  • Removed unnecessary optionals? for values that will always be present in response.
  • Fixes to response serializations.
  • QueryParams support for some requests to avoid unnecessary usage of RequestOptions.
  • IndexExistsRequest support.
  • Refactor ElasticClient class.
  • Fix typos in README.md
  • Improved defaultConverter.
  • Improved Error handling and reporting.
  • Change protocol constraint from Codable to Encodable & Decodable for encode(_:) & decode(data:) respectively.
  • Add serializing error types EncodingError & DecodingError
  • DefaultSerializer test cases

Linux

  • This is the first release tested to be working on Linux (Ubuntu 18.04).
  • Tested to be working with Server-Side frameworks Kitura & Vapor examples will be available soon.

Contributions

  • @lubbo thanks for awesome PR

v1.0.0-alpha.7 - Jul 4, 2019

ChangeLog

  • Rework of the underlying networking layer.
  • This provides the user with the ability to use HttpClient of their choice.
  • swift-nio and URLSession based implementations are available out-of-the-box.
  • URLSession based client as default on iOS, tvOS, and watchOS for backward compatibility.
  • Improved and simpler API.
  • Mechanism to allow the user to use serializer of choice.
  • Way to pass custom Response Converter to get full control on response conversion.
  • A default Response Converter based on Codable.

v1.0.0-alpha.6 - Jun 30, 2019

Changelog

  • Revert pod compatibility for iOS 10+, macOS 10.10+, tvOS 10+, watchOS 3+
  • swift 5.0 required

v1.0.0-alpha.5 - Jun 10, 2019

Changelog

New and improved QueryBuilders, bugfixes fixes, ES 6.8.x compatibility.

Contributions

@lubbo Thanks for opening issues.