├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ └── bug_report.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jazzy.yaml ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Sources └── Elasticsearch │ ├── Client │ ├── ElasticsearchBulk.swift │ ├── ElasticsearchClient+CRUD.swift │ ├── ElasticsearchClient+IndexMgmt.swift │ ├── ElasticsearchClient+Search.swift │ ├── ElasticsearchClient+Suggest.swift │ ├── ElasticsearchClient+connect.swift │ ├── ElasticsearchClient.swift │ └── ElasticsearchLogger.swift │ ├── Database │ ├── ElasticsearchClientConfig.swift │ ├── ElasticsearchDatabase+KeyedCacheSupporting.swift │ ├── ElasticsearchDatabase+LogSupporting.swift │ ├── ElasticsearchDatabase.swift │ └── ElasticsearchProvider.swift │ ├── Index │ ├── Analysis.swift │ ├── Analyzers │ │ ├── Analyzer.swift │ │ ├── CustomAnalyzer.swift │ │ ├── FingerprintAnalyzer.swift │ │ ├── KeywordAnalyzer.swift │ │ ├── PatternAnalyzer.swift │ │ ├── SimpleAnalyzer.swift │ │ ├── StandardAnalyzer.swift │ │ ├── StopAnalyzer.swift │ │ └── WhitespaceAnalyzer.swift │ ├── DefinesAnalysis.swift │ ├── DocumentTypeSettings.swift │ ├── ElasticsearchIndex.swift │ ├── Filters │ │ ├── Character │ │ │ ├── CharacterFilter.swift │ │ │ ├── HTMLStripCharacterFilter.swift │ │ │ ├── MappingCharacterFilter.swift │ │ │ └── PatternReplaceCharacterFilter.swift │ │ └── Token │ │ │ ├── ASCIIFoldingFilter.swift │ │ │ ├── ApostropheFilter.swift │ │ │ ├── ArabicNormalizationFilter.swift │ │ │ ├── ClassicFilter.swift │ │ │ ├── DecimalDigitFilter.swift │ │ │ ├── EdgeNGram.swift │ │ │ ├── GermanNormalizationFilter.swift │ │ │ ├── HindiNormalizationFilter.swift │ │ │ ├── IndicNormalizationFilter.swift │ │ │ ├── KStemFilter.swift │ │ │ ├── LengthFilter.swift │ │ │ ├── LowercaseFilter.swift │ │ │ ├── NGramFilter.swift │ │ │ ├── PersianNormalizationFilter.swift │ │ │ ├── PorterStemFilter.swift │ │ │ ├── ReverseFilter.swift │ │ │ ├── ScandinavianFoldingFilter.swift │ │ │ ├── ScandinavianNormalizationFilter.swift │ │ │ ├── SerbianNormalizationFIlter.swift │ │ │ ├── SoraniNormalizationFilter.swift │ │ │ ├── StandardFilter.swift │ │ │ ├── StemmerFilter+Languages.swift │ │ │ ├── StemmerFilter.swift │ │ │ ├── SynonymFilter.swift │ │ │ ├── TokenFilter.swift │ │ │ ├── TrimFilter.swift │ │ │ └── UppercaseFilter.swift │ ├── IndexMeta.swift │ ├── IndexModifies.swift │ ├── IndexSettings.swift │ ├── MappingTypes │ │ ├── AnyMap.swift │ │ ├── MapBinary.swift │ │ ├── MapBoolean.swift │ │ ├── MapByte.swift │ │ ├── MapCompletionSuggester.swift │ │ ├── MapDate.swift │ │ ├── MapDateRange.swift │ │ ├── MapDouble.swift │ │ ├── MapDoubleRange.swift │ │ ├── MapFloat.swift │ │ ├── MapFloatRange.swift │ │ ├── MapGeoPoint.swift │ │ ├── MapGeoShape.swift │ │ ├── MapHalfFloat.swift │ │ ├── MapIPAddress.swift │ │ ├── MapInteger.swift │ │ ├── MapIntegerRange.swift │ │ ├── MapJoin.swift │ │ ├── MapKeyword.swift │ │ ├── MapLong.swift │ │ ├── MapLongRange.swift │ │ ├── MapNested.swift │ │ ├── MapObject.swift │ │ ├── MapPercolator.swift │ │ ├── MapScaledFloat.swift │ │ ├── MapShort.swift │ │ ├── MapText.swift │ │ ├── MapTokenCount.swift │ │ └── Mappable.swift │ ├── Normalizers │ │ ├── CustomNormalizer.swift │ │ └── Normalizer.swift │ └── Tokenizers │ │ ├── ClassicTokenizer.swift │ │ ├── EdgeNGramTokenizer.swift │ │ ├── KeywordTokenizer.swift │ │ ├── LetterTokenizer.swift │ │ ├── LowercaseTokenizer.swift │ │ ├── NGramTokenizer.swift │ │ ├── PathHierarchyTokenizer.swift │ │ ├── PatternTokenizer.swift │ │ ├── SimplePatternSplitTokenizer.swift │ │ ├── SimplePatternTokenizer.swift │ │ ├── StandardTokenizer.swift │ │ ├── ThaiTokenizer.swift │ │ ├── Tokenizer.swift │ │ ├── UAXURLEmailTokenizer.swift │ │ └── WhitespaceTokenizer.swift │ ├── Model │ ├── Response │ │ ├── AggregationDateHistogramResponse.swift │ │ ├── AggregationExtendedStatsResponse.swift │ │ ├── AggregationGeoBoundsResponse.swift │ │ ├── AggregationGeoCentroidResponse.swift │ │ ├── AggregationHistogramResponse.swift │ │ ├── AggregationResponse.swift │ │ ├── AggregationSingleValueResponse.swift │ │ ├── AggregationStatsResponse.swift │ │ ├── AggregationTermsResponse.swift │ │ ├── AnyAggregationResponse.swift │ │ ├── BulkResponse.swift │ │ ├── DocResponse.swift │ │ ├── IndexResponse.swift │ │ ├── SearchResponse.swift │ │ └── SuggestResponse.swift │ └── SettableID.swift │ ├── Search │ ├── Aggregation │ │ ├── Aggregation.swift │ │ ├── AnyAggregation.swift │ │ ├── BucketAggregations │ │ │ ├── DateHistogramAggregation.swift │ │ │ ├── HistogramAggregation.swift │ │ │ └── TermsAggregation.swift │ │ └── MetricsAggregations │ │ │ ├── AvgAggregation.swift │ │ │ ├── CardinalityAggregation.swift │ │ │ ├── ExtendedStatsAggregation.swift │ │ │ ├── GeoBoundsAggregation.swift │ │ │ ├── GeoCentroidAggregation.swift │ │ │ ├── MaxAggregation.swift │ │ │ ├── MinAggregation.swift │ │ │ ├── StatsAggregation.swift │ │ │ ├── SumAggregation.swift │ │ │ ├── TopHitsAggregation.swift │ │ │ └── ValueCountAggregation.swift │ ├── Decoder+AggregationUserInfo.swift │ ├── Query │ │ ├── AnyQuery.swift │ │ ├── BoolQuery.swift │ │ ├── CommonTerms.swift │ │ ├── Exists.swift │ │ ├── FunctionScore.swift │ │ ├── Fuzzy.swift │ │ ├── Geo │ │ │ ├── GeoHelpers.swift │ │ │ └── GeoPolygon.swift │ │ ├── IDs.swift │ │ ├── Match.swift │ │ ├── MatchAll.swift │ │ ├── MatchNone.swift │ │ ├── MatchPhrase.swift │ │ ├── MatchPhrasePrefix.swift │ │ ├── MultiMatch.swift │ │ ├── Nested.swift │ │ ├── Prefix.swift │ │ ├── Query.swift │ │ ├── Range.swift │ │ ├── Regexp.swift │ │ ├── Score Functions │ │ │ ├── AnyScoreFunction.swift │ │ │ ├── Exp.swift │ │ │ ├── FieldValueFactor.swift │ │ │ ├── Gauss.swift │ │ │ ├── Linear.swift │ │ │ ├── RandomScore.swift │ │ │ ├── ScoreFunction.swift │ │ │ ├── ScriptScore.swift │ │ │ └── WeightScore.swift │ │ ├── ScriptQuery.swift │ │ ├── SpanQueries │ │ │ ├── AnySpanQuery.swift │ │ │ ├── Span.swift │ │ │ ├── SpanContaining.swift │ │ │ ├── SpanFirst.swift │ │ │ ├── SpanNear.swift │ │ │ ├── SpanNot.swift │ │ │ ├── SpanOr.swift │ │ │ ├── SpanTerm.swift │ │ │ └── SpanWithin.swift │ │ ├── Suggest.swift │ │ ├── Term.swift │ │ ├── Terms.swift │ │ └── Wildcard.swift │ ├── Script.swift │ ├── SearchContainer.swift │ ├── Sort │ │ ├── Sort.swift │ │ └── SortOrder.swift │ └── SuggestContainer.swift │ └── Utilities │ ├── DynamicKey.swift │ ├── ElasticsearchError.swift │ └── Exports.swift ├── TODO.md ├── Tests ├── ElasticsearchTests │ ├── Analysis │ │ ├── AnalyzerTests.swift │ │ ├── CharacterFilterTests.swift │ │ ├── NormalizerTests.swift │ │ ├── TokenFilterTests.swift │ │ └── TokenizerTests.swift │ ├── ElasticsearchAggregationCodableTests.swift │ ├── ElasticsearchQueryCodableTests.swift │ ├── ElasticsearchTests.swift │ ├── TestHelpers.swift │ ├── VaporIntegrationTests.swift │ └── XCTestManifests.swift └── LinuxMain.swift └── docs ├── Aggregation Constructors.html ├── Analyzers.html ├── Character Filters.html ├── Classes ├── ElasticsearchBulk.html ├── ElasticsearchClient.html ├── ElasticsearchDatabase.html ├── ElasticsearchIndex.html ├── ElasticsearchIndex │ └── Settings.html └── ElasticsearchProvider.html ├── Client.html ├── Enums ├── GeoValidationMethod.html ├── OperationType.html ├── Operator.html ├── OrderDirection.html ├── SimilarityType.html ├── TermVector.html ├── TextFieldType.html └── TextIndexOptions.html ├── Index Mapping.html ├── Normalizers.html ├── Other Protocols.html ├── Other Structs.html ├── Other Typealiases.html ├── Protocols ├── AggregationResponse.html ├── DefinesAnalyzers.html ├── DefinesCharacterFilters.html ├── DefinesNormalizers.html ├── DefinesTokenFilters.html ├── DefinesTokenizers.html ├── Mappable.html └── SettableID.html ├── Query Constructors.html ├── Response Structures.html ├── Structs ├── ASCIIFoldingFilter.html ├── AggregationBucket.html ├── AggregationExtendedStatsResponse.html ├── AggregationExtendedStatsResponse │ └── StandardDeviationBounds.html ├── AggregationGeoBoundsResponse.html ├── AggregationGeoBoundsResponse │ ├── BoundsContainer.html │ └── BoundsPoint.html ├── AggregationGeoCentroidResponse.html ├── AggregationGeoCentroidResponse │ └── BoundsPoint.html ├── AggregationSingleValueResponse.html ├── AggregationStatsResponse.html ├── AggregationTermsResponse.html ├── Analysis.html ├── ApostropheFilter.html ├── ArabicNormalizationFilter.html ├── AvgAggregation.html ├── BoolQuery.html ├── BulkHeader.html ├── BulkItemResponse.html ├── BulkItemResponse │ ├── ResultType.html │ └── Shards.html ├── BulkResponse.html ├── CardinalityAggregation.html ├── ClassicFilter.html ├── ClassicTokenizer.html ├── CommonTerms.html ├── CustomAnalyzer.html ├── CustomNormalizer.html ├── DecimalDigitFilter.html ├── DocResponse.html ├── EdgeNGramFilter.html ├── EdgeNGramTokenizer.html ├── EdgeNGramTokenizer │ └── CharacterClass.html ├── ElasticsearchClientConfig.html ├── ElasticsearchError.html ├── Exists.html ├── ExtendedStatsAggregation.html ├── FingerprintAnalyzer.html ├── Fuzzy.html ├── GeoBoundsAggregation.html ├── GeoCentroidAggregation.html ├── GeoPoint.html ├── GeoPolygon.html ├── GermanNormalizationFilter.html ├── HTMLStripCharacterFilter.html ├── HindiNormalizationFilter.html ├── IDs.html ├── IndexResponse.html ├── IndexResponse │ ├── ResultType.html │ └── Shards.html ├── IndexSettings.html ├── IndicNormalizationFilter.html ├── KStemFilter.html ├── KeywordAnalyzer.html ├── KeywordTokenizer.html ├── LengthFilter.html ├── LetterTokenizer.html ├── LowercaseFilter.html ├── LowercaseFilter │ └── Language.html ├── LowercaseTokenizer.html ├── MapBinary.html ├── MapBoolean.html ├── MapByte.html ├── MapCompletionSuggester.html ├── MapDate.html ├── MapDateRange.html ├── MapDouble.html ├── MapDoubleRange.html ├── MapFloat.html ├── MapFloatRange.html ├── MapGeoPoint.html ├── MapGeoShape.html ├── MapGeoShape │ ├── GeoShapeOrientation.html │ ├── GeoShapePrecision.html │ ├── GeoShapePrefixTree.html │ └── GeoShapeStrategy.html ├── MapHalfFloat.html ├── MapIPAddress.html ├── MapInteger.html ├── MapIntegerRange.html ├── MapJoin.html ├── MapKeyword.html ├── MapLong.html ├── MapLongRange.html ├── MapNested.html ├── MapObject.html ├── MapPercolator.html ├── MapScaledFloat.html ├── MapShort.html ├── MapText.html ├── MapTokenCount.html ├── MappingCharacterFilter.html ├── Match.html ├── MatchAll.html ├── MatchNone.html ├── MatchPhrase.html ├── MatchPhrasePrefix.html ├── MaxAggregation.html ├── MinAggregation.html ├── MultiMatch.html ├── MultiMatch │ └── Kind.html ├── NGramFilter.html ├── NGramTokenizer.html ├── NGramTokenizer │ └── CharacterClass.html ├── PathHierarchyTokenizer.html ├── PatternAnalyzer.html ├── PatternReplaceCharacterFilter.html ├── PatternTokenizer.html ├── PersianNormalizationFilter.html ├── PorterStemFilter.html ├── Prefix.html ├── Query.html ├── Range.html ├── Regexp.html ├── ReverseFilter.html ├── ScandinavianFoldingFilter.html ├── ScandinavianNormalizationFilter.html ├── Script.html ├── ScriptQuery.html ├── SearchContainer.html ├── SearchResponse.html ├── SearchResponse │ ├── HitsContainer.html │ ├── HitsContainer │ │ └── Hit.html │ └── Shards.html ├── SerbianNormalizationFilter.html ├── SimpleAnalyzer.html ├── SimplePatternSplitTokenizer.html ├── SimplePatternTokenizer.html ├── SoraniNormalizationFilter.html ├── SpanContaining.html ├── SpanFirst.html ├── SpanNear.html ├── SpanNot.html ├── SpanOr.html ├── SpanTerm.html ├── SpanWithin.html ├── StandardAnalyzer.html ├── StandardFilter.html ├── StandardTokenizer.html ├── StatsAggregation.html ├── StopAnalyzer.html ├── SumAggregation.html ├── SynonymFilter.html ├── SynonymFilter │ └── Format.html ├── Term.html ├── Terms.html ├── TermsAggregation.html ├── TermsAggregation │ └── CollectMode.html ├── TextField.html ├── ThaiTokenizer.html ├── TopHitsAggregation.html ├── TrimFilter.html ├── UAXURLEmailTokenizer.html ├── UppercaseFilter.html ├── ValueCountAggregation.html ├── WhitespaceAnalyzer.html ├── WhitespaceTokenizer.html └── Wildcard.html ├── Supporting Structures.html ├── Token Filters.html ├── Tokenizers.html ├── badge.svg ├── css ├── highlight.css └── jazzy.css ├── docsets ├── Elasticsearch.docset │ └── Contents │ │ ├── Info.plist │ │ └── Resources │ │ ├── Documents │ │ ├── Aggregation Constructors.html │ │ ├── Analyzers.html │ │ ├── Character Filters.html │ │ ├── Classes │ │ │ ├── ElasticsearchBulk.html │ │ │ ├── ElasticsearchClient.html │ │ │ ├── ElasticsearchDatabase.html │ │ │ ├── ElasticsearchIndex.html │ │ │ ├── ElasticsearchIndex │ │ │ │ └── Settings.html │ │ │ └── ElasticsearchProvider.html │ │ ├── Client.html │ │ ├── Enums │ │ │ ├── GeoValidationMethod.html │ │ │ ├── OperationType.html │ │ │ ├── Operator.html │ │ │ ├── OrderDirection.html │ │ │ ├── SimilarityType.html │ │ │ ├── TermVector.html │ │ │ ├── TextFieldType.html │ │ │ └── TextIndexOptions.html │ │ ├── Index Mapping.html │ │ ├── Normalizers.html │ │ ├── Other Protocols.html │ │ ├── Other Structs.html │ │ ├── Other Typealiases.html │ │ ├── Protocols │ │ │ ├── AggregationResponse.html │ │ │ ├── DefinesAnalyzers.html │ │ │ ├── DefinesCharacterFilters.html │ │ │ ├── DefinesNormalizers.html │ │ │ ├── DefinesTokenFilters.html │ │ │ ├── DefinesTokenizers.html │ │ │ ├── Mappable.html │ │ │ └── SettableID.html │ │ ├── Query Constructors.html │ │ ├── Response Structures.html │ │ ├── Structs │ │ │ ├── ASCIIFoldingFilter.html │ │ │ ├── AggregationBucket.html │ │ │ ├── AggregationExtendedStatsResponse.html │ │ │ ├── AggregationExtendedStatsResponse │ │ │ │ └── StandardDeviationBounds.html │ │ │ ├── AggregationGeoBoundsResponse.html │ │ │ ├── AggregationGeoBoundsResponse │ │ │ │ ├── BoundsContainer.html │ │ │ │ └── BoundsPoint.html │ │ │ ├── AggregationGeoCentroidResponse.html │ │ │ ├── AggregationGeoCentroidResponse │ │ │ │ └── BoundsPoint.html │ │ │ ├── AggregationSingleValueResponse.html │ │ │ ├── AggregationStatsResponse.html │ │ │ ├── AggregationTermsResponse.html │ │ │ ├── Analysis.html │ │ │ ├── ApostropheFilter.html │ │ │ ├── ArabicNormalizationFilter.html │ │ │ ├── AvgAggregation.html │ │ │ ├── BoolQuery.html │ │ │ ├── BulkHeader.html │ │ │ ├── BulkItemResponse.html │ │ │ ├── BulkItemResponse │ │ │ │ ├── ResultType.html │ │ │ │ └── Shards.html │ │ │ ├── BulkResponse.html │ │ │ ├── CardinalityAggregation.html │ │ │ ├── ClassicFilter.html │ │ │ ├── ClassicTokenizer.html │ │ │ ├── CommonTerms.html │ │ │ ├── CustomAnalyzer.html │ │ │ ├── CustomNormalizer.html │ │ │ ├── DecimalDigitFilter.html │ │ │ ├── DocResponse.html │ │ │ ├── EdgeNGramFilter.html │ │ │ ├── EdgeNGramTokenizer.html │ │ │ ├── EdgeNGramTokenizer │ │ │ │ └── CharacterClass.html │ │ │ ├── ElasticsearchClientConfig.html │ │ │ ├── ElasticsearchError.html │ │ │ ├── Exists.html │ │ │ ├── ExtendedStatsAggregation.html │ │ │ ├── FingerprintAnalyzer.html │ │ │ ├── Fuzzy.html │ │ │ ├── GeoBoundsAggregation.html │ │ │ ├── GeoCentroidAggregation.html │ │ │ ├── GeoPoint.html │ │ │ ├── GeoPolygon.html │ │ │ ├── GermanNormalizationFilter.html │ │ │ ├── HTMLStripCharacterFilter.html │ │ │ ├── HindiNormalizationFilter.html │ │ │ ├── IDs.html │ │ │ ├── IndexResponse.html │ │ │ ├── IndexResponse │ │ │ │ ├── ResultType.html │ │ │ │ └── Shards.html │ │ │ ├── IndexSettings.html │ │ │ ├── IndicNormalizationFilter.html │ │ │ ├── KStemFilter.html │ │ │ ├── KeywordAnalyzer.html │ │ │ ├── KeywordTokenizer.html │ │ │ ├── LengthFilter.html │ │ │ ├── LetterTokenizer.html │ │ │ ├── LowercaseFilter.html │ │ │ ├── LowercaseFilter │ │ │ │ └── Language.html │ │ │ ├── LowercaseTokenizer.html │ │ │ ├── MapBinary.html │ │ │ ├── MapBoolean.html │ │ │ ├── MapByte.html │ │ │ ├── MapCompletionSuggester.html │ │ │ ├── MapDate.html │ │ │ ├── MapDateRange.html │ │ │ ├── MapDouble.html │ │ │ ├── MapDoubleRange.html │ │ │ ├── MapFloat.html │ │ │ ├── MapFloatRange.html │ │ │ ├── MapGeoPoint.html │ │ │ ├── MapGeoShape.html │ │ │ ├── MapGeoShape │ │ │ │ ├── GeoShapeOrientation.html │ │ │ │ ├── GeoShapePrecision.html │ │ │ │ ├── GeoShapePrefixTree.html │ │ │ │ └── GeoShapeStrategy.html │ │ │ ├── MapHalfFloat.html │ │ │ ├── MapIPAddress.html │ │ │ ├── MapInteger.html │ │ │ ├── MapIntegerRange.html │ │ │ ├── MapJoin.html │ │ │ ├── MapKeyword.html │ │ │ ├── MapLong.html │ │ │ ├── MapLongRange.html │ │ │ ├── MapNested.html │ │ │ ├── MapObject.html │ │ │ ├── MapPercolator.html │ │ │ ├── MapScaledFloat.html │ │ │ ├── MapShort.html │ │ │ ├── MapText.html │ │ │ ├── MapTokenCount.html │ │ │ ├── MappingCharacterFilter.html │ │ │ ├── Match.html │ │ │ ├── MatchAll.html │ │ │ ├── MatchNone.html │ │ │ ├── MatchPhrase.html │ │ │ ├── MatchPhrasePrefix.html │ │ │ ├── MaxAggregation.html │ │ │ ├── MinAggregation.html │ │ │ ├── MultiMatch.html │ │ │ ├── MultiMatch │ │ │ │ └── Kind.html │ │ │ ├── NGramFilter.html │ │ │ ├── NGramTokenizer.html │ │ │ ├── NGramTokenizer │ │ │ │ └── CharacterClass.html │ │ │ ├── PathHierarchyTokenizer.html │ │ │ ├── PatternAnalyzer.html │ │ │ ├── PatternReplaceCharacterFilter.html │ │ │ ├── PatternTokenizer.html │ │ │ ├── PersianNormalizationFilter.html │ │ │ ├── PorterStemFilter.html │ │ │ ├── Prefix.html │ │ │ ├── Query.html │ │ │ ├── Range.html │ │ │ ├── Regexp.html │ │ │ ├── ReverseFilter.html │ │ │ ├── ScandinavianFoldingFilter.html │ │ │ ├── ScandinavianNormalizationFilter.html │ │ │ ├── Script.html │ │ │ ├── ScriptQuery.html │ │ │ ├── SearchContainer.html │ │ │ ├── SearchResponse.html │ │ │ ├── SearchResponse │ │ │ │ ├── HitsContainer.html │ │ │ │ ├── HitsContainer │ │ │ │ │ └── Hit.html │ │ │ │ └── Shards.html │ │ │ ├── SerbianNormalizationFilter.html │ │ │ ├── SimpleAnalyzer.html │ │ │ ├── SimplePatternSplitTokenizer.html │ │ │ ├── SimplePatternTokenizer.html │ │ │ ├── SoraniNormalizationFilter.html │ │ │ ├── SpanContaining.html │ │ │ ├── SpanFirst.html │ │ │ ├── SpanNear.html │ │ │ ├── SpanNot.html │ │ │ ├── SpanOr.html │ │ │ ├── SpanTerm.html │ │ │ ├── SpanWithin.html │ │ │ ├── StandardAnalyzer.html │ │ │ ├── StandardFilter.html │ │ │ ├── StandardTokenizer.html │ │ │ ├── StatsAggregation.html │ │ │ ├── StopAnalyzer.html │ │ │ ├── SumAggregation.html │ │ │ ├── SynonymFilter.html │ │ │ ├── SynonymFilter │ │ │ │ └── Format.html │ │ │ ├── Term.html │ │ │ ├── Terms.html │ │ │ ├── TermsAggregation.html │ │ │ ├── TermsAggregation │ │ │ │ └── CollectMode.html │ │ │ ├── TextField.html │ │ │ ├── ThaiTokenizer.html │ │ │ ├── TopHitsAggregation.html │ │ │ ├── TrimFilter.html │ │ │ ├── UAXURLEmailTokenizer.html │ │ │ ├── UppercaseFilter.html │ │ │ ├── ValueCountAggregation.html │ │ │ ├── WhitespaceAnalyzer.html │ │ │ ├── WhitespaceTokenizer.html │ │ │ └── Wildcard.html │ │ ├── Supporting Structures.html │ │ ├── Token Filters.html │ │ ├── Tokenizers.html │ │ ├── css │ │ │ ├── highlight.css │ │ │ └── jazzy.css │ │ ├── img │ │ │ ├── carat.png │ │ │ ├── dash.png │ │ │ └── gh.png │ │ ├── index.html │ │ ├── js │ │ │ ├── jazzy.js │ │ │ └── jquery.min.js │ │ └── search.json │ │ └── docSet.dsidx └── Elasticsearch.tgz ├── img ├── carat.png ├── dash.png └── gh.png ├── index.html ├── js ├── jazzy.js └── jquery.min.js ├── search.json └── undocumented.json /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Swift Elasticsearch client 2 | 3 | First off… awesome! All contributors are welcome! 4 | 5 | Since this project is still fairly young, contributing is also fairly easy. 6 | There's lots to be done by people of all skill levels. More tests can always 7 | be written, more and better documentation can always be provided to users. 8 | 9 | If you have time on your hands and want to find something to contribute, take 10 | a look at the TODO file for ideas on what can be done to help out. 11 | 12 | ## Testing 13 | 14 | Once in Xcode, select the `Vapor-Package` scheme and use `CMD+U` to run the tests. 15 | 16 | When adding new tests, don't forget to add the method name to the `allTests` array. 17 | If you add a new `XCTestCase` subclass, make sure to add it to the `Tests/LinuxMain.swift` file. 18 | 19 | If you are fixing a single GitHub issue in particular, you can add a test named `testGH` to ensure 20 | that your fix is working. This will also help prevent regression. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | 12 | ### Steps to reproduce 13 | 14 | 15 | 16 | 17 | 18 | ### Expected behavior 19 | 20 | 21 | 22 | ### Actual behavior 23 | 24 | 25 | 26 | ### Environment 27 | 28 | 29 | 30 | * Version/commit of the Elasticsearch client you are using 31 | * Version of Elasticsearch that you are using 32 | * Vapor Framework version: 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ### Checklist 7 | 8 | 9 | 10 | - [ ] All tests are passing (code compiles and passes tests). 11 | - [ ] There are no breaking changes to public API. 12 | - [ ] New test cases have been added where appropriate. 13 | - [ ] All new code has been commented with doc blocks `///`. 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 7 | 8 | *.xcodeproj 9 | 10 | ## Build generated 11 | build/ 12 | DerivedData/ 13 | 14 | ## Various settings 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata/ 24 | project.xcworkspace 25 | 26 | ## Other 27 | *.moved-aside 28 | *.xccheckout 29 | *.xcscmblueprint 30 | 31 | ## Obj-C/Swift specific 32 | *.hmap 33 | *.ipa 34 | *.dSYM.zip 35 | *.dSYM 36 | 37 | ## Playgrounds 38 | timeline.xctimeline 39 | playground.xcworkspace 40 | 41 | # Swift Package Manager 42 | # 43 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 44 | # Packages/ 45 | # Package.pins 46 | # Package.resolved 47 | .build/ 48 | 49 | # CocoaPods 50 | # 51 | # We recommend against adding the Pods directory to your .gitignore. However 52 | # you should judge for yourself, the pros and cons are mentioned at: 53 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 54 | # 55 | # Pods/ 56 | 57 | # Carthage 58 | # 59 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 60 | # Carthage/Checkouts 61 | 62 | Carthage/Build 63 | 64 | # fastlane 65 | # 66 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 67 | # screenshots whenever they are needed. 68 | # For more information about the recommended setup visit: 69 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 70 | 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots/**/*.png 74 | fastlane/test_output 75 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ryan Grimm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Elasticsearch", 8 | products: [ 9 | .library(name: "Elasticsearch", targets: ["Elasticsearch"]) 10 | ], 11 | dependencies: [ 12 | // Core extensions, type-aliases, and functions that facilitate common tasks. 13 | .package(url: "https://github.com/vapor/core.git", from: "3.0.0"), 14 | 15 | // Crypto goodies 16 | .package(url: "https://github.com/vapor/crypto.git", from: "3.2.0"), 17 | 18 | // Core services for creating database integrations. 19 | .package(url: "https://github.com/vapor/database-kit.git", from: "1.0.0"), 20 | 21 | // Event-driven network application framework for high performance protocol servers & clients, non-blocking. 22 | .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), 23 | 24 | // Grab the HTTP goodies from Vapor 25 | .package(url: "https://github.com/vapor/http.git", from: "3.0.0"), 26 | 27 | // Grab Vapor itself for testing 28 | .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), 29 | ], 30 | targets: [ 31 | .target( name: "Elasticsearch", dependencies: ["Crypto", "Async", "Bits", "DatabaseKit", "Debugging", "NIO", "COperatingSystem", "HTTP"]), 32 | .testTarget( name: "ElasticsearchTests", dependencies: ["Elasticsearch", "Vapor"]) 33 | ] 34 | ) 35 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Client/ElasticsearchClient+IndexMgmt.swift: -------------------------------------------------------------------------------- 1 | import Async 2 | 3 | extension ElasticsearchClient { 4 | public func fetchIndex(name: String) -> Future { 5 | return ElasticsearchIndex.fetch(indexName: name, client: self) 6 | } 7 | 8 | public func configureIndex(name: String) -> ElasticsearchIndex { 9 | return ElasticsearchIndex(indexName: name) 10 | } 11 | 12 | public func deleteIndex(name: String) -> Future { 13 | return ElasticsearchIndex.delete(indexName: name, client: self) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Client/ElasticsearchClient+Search.swift: -------------------------------------------------------------------------------- 1 | import HTTP 2 | 3 | /** 4 | Search methods. 5 | */ 6 | extension ElasticsearchClient { 7 | /// Execute a search in a given index 8 | /// 9 | /// - Parameters: 10 | /// - decodeTo: A struct or class that conforms to the Decodable protocol and can properly decode the documents stored in the index 11 | /// - index: The index to execute the query against 12 | /// - query: A SearchContainer object that specifies the query to execute 13 | /// - type: The index type (defaults to _doc) 14 | /// - routing: Routing information 15 | /// - Returns: A Future SearchResponse 16 | public func search( 17 | decodeTo: U.Type, 18 | index: String, 19 | query: SearchContainer, 20 | type: String = "_doc", 21 | routing: String? = nil 22 | ) -> Future> { 23 | let body: Data 24 | do { 25 | body = try self.encoder.encode(query) 26 | } catch { 27 | return worker.future(error: error) 28 | } 29 | let url = ElasticsearchClient.generateURL(path: "/\(index)/\(type)/_search", routing: routing) 30 | return send(HTTPMethod.POST, to: url.string!, with: body).map(to: SearchResponse.self) {jsonData in 31 | let decoder = JSONDecoder() 32 | if let aggregations = query.aggs { 33 | if aggregations.count > 0 { 34 | decoder.userInfo(fromAggregations: aggregations) 35 | } 36 | } 37 | 38 | if let jsonData = jsonData { 39 | return try decoder.decode(SearchResponse.self, from: jsonData) 40 | } 41 | 42 | throw ElasticsearchError(identifier: "search_failed", reason: "Could not execute search", source: .capture(), statusCode: 404) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Client/ElasticsearchClient+Suggest.swift: -------------------------------------------------------------------------------- 1 | import HTTP 2 | 3 | /** 4 | Suggest methods. 5 | */ 6 | extension ElasticsearchClient { 7 | /// Execute a suggest search in a given index 8 | /// 9 | /// - Parameters: 10 | /// - index: The index to execute the query against 11 | /// - query: A SearchContainer object that specifies the query to execute 12 | /// - type: The index type (defaults to _doc) 13 | /// - routing: Routing information 14 | /// - Returns: A Future SearchResponse 15 | public func suggest( 16 | index: String, 17 | query: SuggestContainer, 18 | type: String = "_doc", 19 | routing: String? = nil 20 | ) -> Future { 21 | let body: Data 22 | do { 23 | body = try self.encoder.encode(query) 24 | } catch { 25 | return worker.future(error: error) 26 | } 27 | let url = ElasticsearchClient.generateURL(path: "/\(index)/\(type)/_search", routing: routing) 28 | 29 | return send(HTTPMethod.POST, to: url.string!, with: body).map { jsonData in 30 | let decoder = JSONDecoder() 31 | 32 | if let jsonData = jsonData { 33 | return try decoder.decode(SuggestResponse.self, from: jsonData) 34 | } 35 | 36 | throw ElasticsearchError(identifier: "search_failed", reason: "Could not execute suggest", source: .capture(), statusCode: 404) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Client/ElasticsearchClient+connect.swift: -------------------------------------------------------------------------------- 1 | import Async 2 | import HTTP 3 | 4 | /** 5 | Connection methods 6 | */ 7 | extension ElasticsearchClient { 8 | /// Connects to a Elasticsearch server over HTTP. 9 | /// 10 | /// - Parameters: 11 | /// - config: The connection configuration to use 12 | /// - worker: The worker to execute with 13 | /// - Returns: An ElasticsearchClient Future 14 | public static func connect( 15 | config: ElasticsearchClientConfig, 16 | on worker: Worker 17 | ) -> Future { 18 | let clientPromise = worker.eventLoop.newPromise(ElasticsearchClient.self) 19 | let scheme: HTTPScheme = config.useSSL ? .https : .http 20 | HTTPClient.connect(scheme: scheme, hostname: config.hostname, port: config.port, on: worker) { error in 21 | let esError = ElasticsearchError(identifier: "connection_failed", reason: "Could not connect to Elasticsearch: " + error.localizedDescription, source: .capture()) 22 | clientPromise.fail(error: esError) 23 | }.do() { client in 24 | let esClient = ElasticsearchClient.init(client: client, config: config, worker: worker) 25 | esClient.isConnected = true 26 | clientPromise.succeed(result: esClient) 27 | }.catch { error in 28 | let esError = ElasticsearchError(identifier: "connection_failed", reason: "Could not connect to Elasticsearch: " + error.localizedDescription, source: .capture()) 29 | clientPromise.fail(error: esError) 30 | } 31 | 32 | return clientPromise.futureResult 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Client/ElasticsearchLogger.swift: -------------------------------------------------------------------------------- 1 | import Async 2 | 3 | /// An Elasticsearch logger. 4 | public protocol ElasticsearchLogger { 5 | /// Log the request/response. 6 | func log(query: String) 7 | } 8 | 9 | extension DatabaseLogger: ElasticsearchLogger { 10 | public func log(query: String) { 11 | record(query: query, values: []) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Database/ElasticsearchClientConfig.swift: -------------------------------------------------------------------------------- 1 | import DatabaseKit 2 | 3 | /// Config options for an `ElasticsearchClient`. 4 | public struct ElasticsearchClientConfig: Service { 5 | /// The Elasticsearch server's hostname. 6 | public var hostname: String 7 | 8 | /// The Elasticsearch server's port. 9 | public var port: Int 10 | 11 | /// Connect using SSL (defaults to false). 12 | public var useSSL = false 13 | 14 | /// The Elasticsearch server's optional username. 15 | public var username: String? 16 | 17 | /// The Elasticsearch server's optional password. 18 | public var password: String? 19 | 20 | /// If wanting to use Elasticsearch as a key/value store `enableKeyedCache` must be set to `true`. 21 | /// This will create a new index in Elasticsearch automatically. By default the name of this 22 | /// index is "_vapor_keyed_cache" but can be controlled via the `keyedCacheIndexName`. 23 | /// If `enableKeyedCache` was set to `true` and then later set to `false`, the Elasticsearch 24 | /// index will be deleted. 25 | public var enableKeyedCache: Bool = false 26 | 27 | /// Name of the index to use for the keyed cache 28 | public var keyedCacheIndexName: String = "vapor_keyed_cache" 29 | 30 | /// Create a new `ElasticsearchClientConfig` from a URL 31 | public init(url: URL) { 32 | self.hostname = url.host ?? "localhost" 33 | self.port = url.port ?? 9200 34 | self.username = url.user 35 | self.password = url.password 36 | } 37 | 38 | /// Create a new `ElasticsearchClientConfig` 39 | public init(hostname: String = "localhost", port: Int = 9200) { 40 | self.hostname = hostname 41 | self.port = port 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Database/ElasticsearchDatabase+KeyedCacheSupporting.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import DatabaseKit 3 | 4 | extension ElasticsearchDatabase: KeyedCacheSupporting { 5 | static func setupKeyedCache(client: ElasticsearchClient, on worker: Worker) -> Future { 6 | if client.config.enableKeyedCache == false { 7 | return .done(on: worker) 8 | } 9 | 10 | client.logger?.record(query: "Keyed cached is enabled") 11 | 12 | return client.fetchIndex(name: client.config.keyedCacheIndexName).flatMap { index -> Future in 13 | if index != nil { 14 | client.logger?.record(query: "Keyed cache index exists") 15 | return .done(on: worker) 16 | } 17 | 18 | let index = client.configureIndex(name: client.config.keyedCacheIndexName) 19 | index.mappings.doc.enabled = false 20 | index.mappings.doc.dynamic = true 21 | return index.create(client: client) 22 | } 23 | } 24 | 25 | public static func keyedCacheGet(_ key: String, as decodable: D.Type, on conn: ElasticsearchClient) throws -> EventLoopFuture where D : Decodable { 26 | return conn.get(decodeTo: D.self, index: conn.config.keyedCacheIndexName, id: key).map(to: D?.self) { result in 27 | if let result = result { 28 | return result.source 29 | } 30 | return nil 31 | } 32 | } 33 | 34 | public static func keyedCacheSet(_ key: String, to encodable: E, on conn: ElasticsearchClient) throws -> EventLoopFuture where E : Encodable { 35 | return conn.index(doc: encodable, index: conn.config.keyedCacheIndexName, id: key).map(to: Void.self, { _ in 36 | return 37 | }) 38 | } 39 | 40 | public static func keyedCacheRemove(_ key: String, on conn: ElasticsearchClient) throws -> EventLoopFuture { 41 | return conn.delete(index: conn.config.keyedCacheIndexName, id: key).map(to: Void.self) { _ in 42 | return 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Database/ElasticsearchDatabase+LogSupporting.swift: -------------------------------------------------------------------------------- 1 | extension ElasticsearchDatabase: LogSupporting { 2 | /// See `LogSupporting`. 3 | public static func enableLogging(_ logger: DatabaseLogger, on conn: ElasticsearchDatabase.Connection) { 4 | conn.logger = logger 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Database/ElasticsearchDatabase.swift: -------------------------------------------------------------------------------- 1 | import DatabaseKit 2 | import Async 3 | 4 | public final class ElasticsearchDatabase: Database { 5 | public typealias Connection = ElasticsearchClient 6 | 7 | /// This client's configuration. 8 | public let config: ElasticsearchClientConfig 9 | 10 | /// Creates a new `ElasticsearchDatabase`. 11 | public init(config: ElasticsearchClientConfig) { 12 | self.config = config 13 | } 14 | 15 | public init(url: URL) { 16 | self.config = ElasticsearchClientConfig(url: url) 17 | } 18 | 19 | /// See `Database`. 20 | public func newConnection(on worker: Worker) -> Future { 21 | return ElasticsearchClient.connect(config: config, on: worker) 22 | } 23 | } 24 | 25 | /// :nodoc: 26 | extension DatabaseIdentifier { 27 | /// Default identifier for `ElasticsearchClient`. 28 | public static var elasticsearch: DatabaseIdentifier { 29 | return .init("elasticsearch") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Analyzers/Analyzer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// :nodoc: 4 | public protocol Analyzer: Codable { 5 | static var typeKey: AnalyzerType { get } 6 | var name: String { get } 7 | } 8 | 9 | /// :nodoc: 10 | public protocol BuiltinAnalyzer { 11 | init() 12 | } 13 | 14 | /// :nodoc: 15 | public enum AnalyzerType: String, Codable { 16 | case standard 17 | case simple 18 | case whitespace 19 | case stop 20 | case keyword 21 | case pattern 22 | case fingerprint 23 | case custom 24 | 25 | var metatype: Analyzer.Type { 26 | switch self { 27 | case .standard: 28 | return StandardAnalyzer.self 29 | case .simple: 30 | return SimpleAnalyzer.self 31 | case .whitespace: 32 | return WhitespaceAnalyzer.self 33 | case .stop: 34 | return StopAnalyzer.self 35 | case .keyword: 36 | return KeywordAnalyzer.self 37 | case .pattern: 38 | return PatternAnalyzer.self 39 | case .fingerprint: 40 | return FingerprintAnalyzer.self 41 | case .custom: 42 | return CustomAnalyzer.self 43 | } 44 | } 45 | 46 | enum Builtins: String, CodingKey { 47 | case standard 48 | case simple 49 | case whitespace 50 | case keyword 51 | 52 | var metatype: BuiltinAnalyzer.Type { 53 | switch self { 54 | case .standard: 55 | return StandardAnalyzer.self 56 | case .simple: 57 | return SimpleAnalyzer.self 58 | case .whitespace: 59 | return WhitespaceAnalyzer.self 60 | case .keyword: 61 | return KeywordAnalyzer.self 62 | } 63 | } 64 | } 65 | } 66 | 67 | /// :nodoc: 68 | internal struct AnyAnalyzer : Codable { 69 | var base: Analyzer 70 | 71 | init(_ base: Analyzer) { 72 | self.base = base 73 | } 74 | 75 | /// :nodoc: 76 | public init(from decoder: Decoder) throws { 77 | let container = try decoder.container(keyedBy: DynamicKey.self) 78 | 79 | let type = try container.decode(AnalyzerType.self, forKey: DynamicKey(stringValue: "type")!) 80 | self.base = try type.metatype.init(from: decoder) 81 | } 82 | 83 | /// :nodoc: 84 | public func encode(to encoder: Encoder) throws { 85 | try base.encode(to: encoder) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Analyzers/KeywordAnalyzer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The keyword analyzer is a “noop” analyzer which returns the entire input string as a single token. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/analysis-keyword-analyzer.html) 8 | */ 9 | public struct KeywordAnalyzer: Analyzer, BuiltinAnalyzer { 10 | /// :nodoc: 11 | public static var typeKey = AnalyzerType.keyword 12 | 13 | /// Holds the string that Elasticsearch uses to identify the analyzer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Analyzers/SimpleAnalyzer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The simple analyzer breaks text into terms whenever it encounters a character which is not a letter. All terms are lower cased. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/analysis-simple-analyzer.html) 8 | */ 9 | public struct SimpleAnalyzer: Analyzer, BuiltinAnalyzer { 10 | /// :nodoc: 11 | public static var typeKey = AnalyzerType.simple 12 | 13 | /// Holds the string that Elasticsearch uses to identify the analyzer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Analyzers/StopAnalyzer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The stop analyzer is the same as the simple analyzer but adds support for removing stop words. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/analysis-stop-analyzer.html) 8 | */ 9 | public struct StopAnalyzer: Analyzer { 10 | /// :nodoc: 11 | public static var typeKey = AnalyzerType.stop 12 | 13 | /// Holds the string that Elasticsearch uses to identify the analyzer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let stopwords: [String]? 17 | public let stopwordsPath: String? 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case type 21 | case stopwords 22 | case stopwordsPath = "stopwords_path" 23 | } 24 | 25 | public init(name: String, stopwords: [String]) { 26 | self.name = name 27 | self.stopwords = stopwords 28 | self.stopwordsPath = nil 29 | } 30 | 31 | public init(name: String, stopwordsPath: String? = nil) { 32 | self.name = name 33 | self.stopwords = nil 34 | self.stopwordsPath = stopwordsPath 35 | } 36 | 37 | /// :nodoc: 38 | public init(from decoder: Decoder) throws { 39 | let container = try decoder.container(keyedBy: CodingKeys.self) 40 | self.name = (decoder.codingPath.last?.stringValue)! 41 | 42 | self.stopwords = try container.decodeIfPresent([String].self, forKey: .stopwords) 43 | self.stopwordsPath = try container.decodeIfPresent(String.self, forKey: .stopwordsPath) 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Analyzers/WhitespaceAnalyzer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The whitespace analyzer breaks text into terms whenever it encounters a whitespace character. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/analysis-whitespace-analyzer.html) 8 | */ 9 | public struct WhitespaceAnalyzer: Analyzer, BuiltinAnalyzer { 10 | /// :nodoc: 11 | public static var typeKey = AnalyzerType.whitespace 12 | 13 | /// Holds the string that Elasticsearch uses to identify the analyzer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/DefinesAnalysis.swift: -------------------------------------------------------------------------------- 1 | 2 | public protocol DefinesAnalyzers { 3 | func definedAnalyzers() -> [Analyzer] 4 | } 5 | 6 | public protocol DefinesTokenizers { 7 | func definedTokenizers() -> [Tokenizer] 8 | } 9 | 10 | public protocol DefinesNormalizers { 11 | func definedNormalizers() -> [Normalizer] 12 | } 13 | 14 | public protocol DefinesCharacterFilters { 15 | func definedCharacterFilters() -> [CharacterFilter] 16 | } 17 | 18 | public protocol DefinesTokenFilters { 19 | func definedTokenFilters() -> [TokenFilter] 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/DocumentTypeSettings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct DocumentTypeSettings: Codable { 4 | var properties = [String: Mappable]() 5 | var enabled = true 6 | var dynamic = false 7 | var meta: IndexMeta? 8 | 9 | enum CodingKeys: String, CodingKey { 10 | case properties 11 | case enabled 12 | case dynamic 13 | case meta = "_meta" 14 | } 15 | 16 | init() { 17 | self.meta = IndexMeta() 18 | } 19 | 20 | init(from decoder: Decoder) throws { 21 | let container = try decoder.container(keyedBy: CodingKeys.self) 22 | 23 | if decoder.analysis() == nil { 24 | return 25 | } 26 | 27 | if container.contains(.properties) { 28 | self.properties = try container.decode([String: AnyMap].self, forKey: .properties).mapValues { $0.base } 29 | } 30 | self.meta = try container.decodeIfPresent(IndexMeta.self, forKey: .meta) 31 | 32 | if container.contains(.enabled) { 33 | do { 34 | self.enabled = (try container.decode(Bool.self, forKey: .enabled)) 35 | } 36 | catch { 37 | self.enabled = try container.decode(String.self, forKey: .enabled) == "true" 38 | } 39 | } 40 | if container.contains(.dynamic) { 41 | do { 42 | self.dynamic = (try container.decode(Bool.self, forKey: .dynamic)) 43 | } 44 | catch { 45 | self.dynamic = try container.decode(String.self, forKey: .dynamic) == "true" 46 | } 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public func encode(to encoder: Encoder) throws { 52 | var container = encoder.container(keyedBy: CodingKeys.self) 53 | 54 | try container.encode(properties.mapValues { AnyMap($0) }, forKey: .properties) 55 | try container.encodeIfPresent(dynamic, forKey: .dynamic) 56 | try container.encodeIfPresent(enabled, forKey: .enabled) 57 | try container.encodeIfPresent(meta, forKey: .meta) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Character/CharacterFilter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// :nodoc: 5 | public protocol CharacterFilter: Codable { 6 | static var typeKey: CharacterFilterType { get } 7 | var name: String { get } 8 | } 9 | 10 | /// :nodoc: 11 | public protocol BuiltinCharacterTokenFilter { 12 | init() 13 | } 14 | 15 | /// :nodoc: 16 | public enum CharacterFilterType: String, Codable { 17 | case htmlStrip = "html_strip" 18 | case mapping 19 | case patternReplace = "pattern_replace" 20 | 21 | var metatype: CharacterFilter.Type { 22 | switch self { 23 | case .htmlStrip: 24 | return HTMLStripCharacterFilter.self 25 | case .mapping: 26 | return MappingCharacterFilter.self 27 | case .patternReplace: 28 | return PatternReplaceCharacterFilter.self 29 | } 30 | } 31 | 32 | enum Builtins: String, CodingKey { 33 | case htmlStrip = "html_strip" 34 | 35 | var metatype: BuiltinCharacterTokenFilter.Type { 36 | switch self { 37 | case .htmlStrip: 38 | return HTMLStripCharacterFilter.self 39 | } 40 | } 41 | } 42 | } 43 | 44 | /// :nodoc: 45 | internal struct AnyCharacterFilter : Codable { 46 | var base: CharacterFilter 47 | 48 | init(_ base: CharacterFilter) { 49 | self.base = base 50 | } 51 | 52 | /// :nodoc: 53 | public init(from decoder: Decoder) throws { 54 | let container = try decoder.container(keyedBy: DynamicKey.self) 55 | 56 | let type = try container.decode(CharacterFilterType.self, forKey: DynamicKey(stringValue: "type")!) 57 | self.base = try type.metatype.init(from: decoder) 58 | } 59 | 60 | /// :nodoc: 61 | public func encode(to encoder: Encoder) throws { 62 | try base.encode(to: encoder) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Character/HTMLStripCharacterFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The HTML strip character filter strips HTML elements from the text and replaces HTML entities with their decoded value (e.g. replacing & with &). 6 | 7 | [More Information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-htmlstrip-charfilter.html) 8 | */ 9 | public struct HTMLStripCharacterFilter: CharacterFilter, BuiltinCharacterTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = CharacterFilterType.htmlStrip 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let escapedTags: [String]? 17 | 18 | let isCustom: Bool 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case escapedTags = "escaped_tags" 23 | } 24 | 25 | public init() { 26 | self.name = type 27 | self.isCustom = false 28 | self.escapedTags = nil 29 | } 30 | 31 | public init(name: String, escapedTags: [String]) { 32 | self.name = name 33 | self.escapedTags = escapedTags 34 | self.isCustom = true 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | if self.isCustom { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(type, forKey: .type) 42 | try container.encode(escapedTags, forKey: .escapedTags) 43 | } 44 | else { 45 | var container = encoder.singleValueContainer() 46 | try container.encode(type) 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.escapedTags = try container.decodeIfPresent([String].self, forKey: .escapedTags) 56 | self.isCustom = true 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Character/MappingCharacterFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The mapping character filter accepts a map of keys and values. Whenever it encounters a string of characters that is the same as a key, it replaces them with the value associated with that key. 6 | 7 | Matching is greedy; the longest pattern matching at a given point wins. Replacements are allowed to be the empty string. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html) 10 | */ 11 | public struct MappingCharacterFilter: CharacterFilter { 12 | /// :nodoc: 13 | public static var typeKey = CharacterFilterType.mapping 14 | 15 | /// Holds the string that Elasticsearch uses to identify the filter type 16 | public let type = typeKey.rawValue 17 | public let name: String 18 | public let mappings: [String: String]? 19 | public let mappingsPath: String? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case mappings 24 | case mappingsPath = "mappings_path" 25 | } 26 | 27 | public init(name: String, mappings: [String: String]) { 28 | self.name = name 29 | self.mappings = mappings 30 | self.mappingsPath = nil 31 | } 32 | 33 | public init(name: String, mappingsPath: String) { 34 | self.name = name 35 | self.mappings = nil 36 | self.mappingsPath = mappingsPath 37 | } 38 | 39 | /// :nodoc: 40 | public init(from decoder: Decoder) throws { 41 | let container = try decoder.container(keyedBy: CodingKeys.self) 42 | self.name = (decoder.codingPath.last?.stringValue)! 43 | 44 | self.mappings = try container.decodeIfPresent([String: String].self, forKey: .mappings) 45 | self.mappingsPath = try container.decodeIfPresent(String.self, forKey: .mappingsPath) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Character/PatternReplaceCharacterFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The pattern replace character filter uses a regular expression to match characters which should be replaced with the specified replacement string. The replacement string can refer to capture groups in the regular expression. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pattern-replace-charfilter.html) 8 | */ 9 | public struct PatternReplaceCharacterFilter: CharacterFilter { 10 | /// :nodoc: 11 | public static var typeKey = CharacterFilterType.patternReplace 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public var pattern: String 17 | public var replacement: String 18 | public var flags: String? 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case pattern 23 | case replacement 24 | case flags 25 | } 26 | 27 | public init(name: String, pattern: String, replacement: String, flags: String? = nil) { 28 | self.name = name 29 | self.pattern = pattern 30 | self.replacement = replacement 31 | self.flags = flags 32 | } 33 | 34 | /// :nodoc: 35 | public init(from decoder: Decoder) throws { 36 | let container = try decoder.container(keyedBy: CodingKeys.self) 37 | self.name = (decoder.codingPath.last?.stringValue)! 38 | 39 | self.pattern = try container.decode(String.self, forKey: .pattern) 40 | self.replacement = try container.decode(String.self, forKey: .replacement) 41 | self.flags = try container.decodeIfPresent(String.self, forKey: .flags) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ASCIIFoldingFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type asciifolding that converts alphabetic, numeric, and symbolic Unicode characters which are not in the first 127 ASCII characters (the "Basic Latin" Unicode block) into their ASCII equivalents, if one exists. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-asciifolding-tokenfilter.html) 8 | */ 9 | public struct ASCIIFoldingFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.asciiFolding 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ApostropheFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The apostrophe token filter strips all characters after an apostrophe, including the apostrophe itself. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-apostrophe-tokenfilter.html) 8 | */ 9 | public struct ApostropheFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.apostrophe 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ArabicNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ArabicNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.arabicNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ClassicFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The classic token filter does optional post-processing of terms that are generated by the classic tokenizer. 6 | 7 | This filter removes the english possessive from the end of words, and it removes dots from acronyms. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-classic-tokenfilter.html) 10 | */ 11 | public struct ClassicFilter: BasicTokenFilter, BuiltinTokenFilter { 12 | /// :nodoc: 13 | public static var typeKey = TokenFilterType.classic 14 | 15 | /// Holds the string that Elasticsearch uses to identify the filter type 16 | public let type = typeKey.rawValue 17 | /// :nodoc: 18 | public let name: String 19 | 20 | public init() { 21 | self.name = self.type 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/DecimalDigitFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The decimal digit token filter folds unicode digits to 0-9 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-decimal-digit-tokenfilter.html) 8 | */ 9 | public struct DecimalDigitFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.decimalDigit 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/EdgeNGram.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type edgeNGram. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenfilter.html) 8 | */ 9 | public struct EdgeNGramFilter: TokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.edgeNGram 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let minGram: Int 17 | public let maxGram: Int 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case type 21 | case minGram = "min_gram" 22 | case maxGram = "max_gram" 23 | } 24 | 25 | public init(name: String, minGram: Int, maxGram: Int) { 26 | self.name = name 27 | self.minGram = minGram 28 | self.maxGram = maxGram 29 | } 30 | 31 | /// :nodoc: 32 | public init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: CodingKeys.self) 34 | self.name = (decoder.codingPath.last?.stringValue)! 35 | 36 | self.minGram = try container.decode(Int.self, forKey: .minGram) 37 | self.maxGram = try container.decode(Int.self, forKey: .maxGram) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/GermanNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct GermanNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.germanNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/HindiNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct HindiNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.hindiNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/IndicNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct IndicNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.indicNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/KStemFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The kstem token filter is a high performance filter for english. All terms must already be lowercased (use lowercase filter) for this filter to work correctly. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-kstem-tokenfilter.html) 8 | */ 9 | public struct KStemFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.kStem 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/LengthFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type length that removes words that are too long or too short for the stream. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-length-tokenfilter.html) 8 | */ 9 | public struct LengthFilter: TokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.length 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let min: Int 17 | public let max: Int 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case type 21 | case min 22 | case max 23 | } 24 | 25 | public init(name: String, min: Int, max: Int) { 26 | self.name = name 27 | self.min = min 28 | self.max = max 29 | } 30 | 31 | /// :nodoc: 32 | public init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: CodingKeys.self) 34 | self.name = (decoder.codingPath.last?.stringValue)! 35 | 36 | self.min = try container.decode(Int.self, forKey: .min) 37 | self.max = try container.decode(Int.self, forKey: .max) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/LowercaseFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type lowercase that normalizes token text to lower case. 6 | 7 | Lowercase token filter supports Greek, Irish, and Turkish lowercase token filters through the language parameter. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenfilter.html) 10 | */ 11 | public struct LowercaseFilter: TokenFilter, BuiltinTokenFilter { 12 | /// :nodoc: 13 | public static var typeKey = TokenFilterType.lowercase 14 | 15 | /// Holds the string that Elasticsearch uses to identify the filter type 16 | public let type = typeKey.rawValue 17 | public let name: String 18 | public let language: Language? 19 | 20 | let isCustom: Bool 21 | 22 | public enum Language: String, Codable { 23 | case greek 24 | case irish 25 | case turkish 26 | } 27 | 28 | enum CodingKeys: String, CodingKey { 29 | case type 30 | case language 31 | } 32 | 33 | public init() { 34 | self.name = type 35 | self.language = nil 36 | self.isCustom = false 37 | } 38 | 39 | public init(name: String, language: Language) { 40 | self.name = name 41 | self.language = language 42 | self.isCustom = true 43 | } 44 | 45 | /// :nodoc: 46 | public func encode(to encoder: Encoder) throws { 47 | if self.isCustom { 48 | var container = encoder.container(keyedBy: CodingKeys.self) 49 | try container.encode(type, forKey: .type) 50 | try container.encode(language, forKey: .language) 51 | } 52 | else { 53 | var container = encoder.singleValueContainer() 54 | try container.encode(type) 55 | } 56 | } 57 | 58 | /// :nodoc: 59 | public init(from decoder: Decoder) throws { 60 | let container = try decoder.container(keyedBy: CodingKeys.self) 61 | self.name = (decoder.codingPath.last?.stringValue)! 62 | 63 | self.language = try container.decodeIfPresent(Language.self, forKey: .language) 64 | self.isCustom = true 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/NGramFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type nGram. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenfilter.html) 8 | */ 9 | public struct NGramFilter: TokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.nGram 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let minGram: Int 17 | public let maxGram: Int 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case type 21 | case minGram = "min_gram" 22 | case maxGram = "max_gram" 23 | } 24 | 25 | public init(name: String, minGram: Int, maxGram: Int) { 26 | self.name = name 27 | self.minGram = minGram 28 | self.maxGram = maxGram 29 | } 30 | 31 | /// :nodoc: 32 | public init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: CodingKeys.self) 34 | self.name = (decoder.codingPath.last?.stringValue)! 35 | 36 | self.minGram = try container.decode(Int.self, forKey: .minGram) 37 | self.maxGram = try container.decode(Int.self, forKey: .maxGram) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/PersianNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct PersianNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.persianNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/PorterStemFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type porter_stem that transforms the token stream as per the Porter stemming algorithm. 6 | 7 | Note, the input to the stemming filter must already be in lower case, so you will need to use Lower Case Token Filter or Lower Case Tokenizer farther down the Tokenizer chain in order for this to work properly!. For example, when using custom analyzer, make sure the lowercase filter comes before the porter_stem filter in the list of filters. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-porterstem-tokenfilter.html) 10 | */ 11 | public struct PorterStemFilter: BasicTokenFilter, BuiltinTokenFilter { 12 | /// :nodoc: 13 | public static var typeKey = TokenFilterType.porterStem 14 | 15 | /// Holds the string that Elasticsearch uses to identify the filter type 16 | public let type = typeKey.rawValue 17 | /// :nodoc: 18 | public let name: String 19 | 20 | public init() { 21 | self.name = self.type 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ReverseFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type reverse that simply reverses each token. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-reverse-tokenfilter.html) 8 | */ 9 | public struct ReverseFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.reverse 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ScandinavianFoldingFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ScandinavianFoldingFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.scandinavianFolding 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/ScandinavianNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct ScandinavianNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.scandinavianNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/SerbianNormalizationFIlter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct SerbianNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.serbianNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/SoraniNormalizationFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct SoraniNormalizationFilter: BasicTokenFilter, BuiltinTokenFilter { 5 | /// :nodoc: 6 | public static var typeKey = TokenFilterType.soraniNormalization 7 | 8 | /// Holds the string that Elasticsearch uses to identify the filter type 9 | public let type = typeKey.rawValue 10 | /// :nodoc: 11 | public let name: String 12 | 13 | public init() { 14 | self.name = self.type 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/StandardFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type standard that normalizes tokens extracted with the standard tokenizer. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenfilter.html) 8 | */ 9 | public struct StandardFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.standard 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/StemmerFilter+Languages.swift: -------------------------------------------------------------------------------- 1 | extension StemmerFilter { 2 | 3 | /** 4 | Contains all possible languages for stemmer filter (see `StemmerFilter`) 5 | 6 | [More Information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stemmer-tokenfilter.html) 7 | */ 8 | public enum Language: String, Codable { 9 | 10 | case arabic 11 | case armenian 12 | case basque 13 | case bengali 14 | case bengaliLight = "light_bengali" 15 | case brazilian 16 | case bulgarian 17 | case catalan 18 | case czech 19 | case danish 20 | case dutch 21 | case dutchKraaijPohlmann = "dutch_kp" 22 | case english 23 | case englishLight = "light_english" 24 | case englishMinimal = "minimal_english" 25 | case englishPossessive = "possessive_english" 26 | case englishPorter2 = "porter2" 27 | case englishLovins = "lovins" 28 | case finnish 29 | case finnishLight = "light_finnish" 30 | case french 31 | case frenchLight = "light_french" 32 | case frenchMinimal = "minimal_french" 33 | case galician 34 | case galicianMinimal = "minimal_galician" 35 | case german 36 | case german2 37 | case germanLight = "light_german" 38 | case germanMinimal = "minimal_germann" 39 | case greek 40 | case hindi 41 | case hungarian 42 | case hungarianLight = "light_hungarian" 43 | case indonesian 44 | case irish 45 | case italian 46 | case italianLight = "light_italian" 47 | case sorani 48 | case latvian 49 | case lithuanian 50 | case norwegian 51 | case norwegianLight = "light_norwegian" 52 | case norwegianMinimal = "minimal_norwegian" 53 | case norwegianNynorskLight = "light_nynorsk" 54 | case norwegianNynorskMinimal = "minimal_nynorsk" 55 | case portuguese = "portuguese" 56 | case portugueseLight = "light_portuguese" 57 | case portugueseMinimal = "minimal_portuguese" 58 | case portugueseRSLP = "portuguese_rslp" 59 | case romanian 60 | case russian 61 | case russianLight = "light_russian" 62 | case spanish 63 | case spanishLight = "light_spanish" 64 | case swedish 65 | case swedishLight = "light_swedish" 66 | case turkish 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/StemmerFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A filter that provides access to (almost) all of the available stemming token filters through a single unified interface. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stemmer-tokenfilter.html) 8 | */ 9 | public struct StemmerFilter: TokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.stemmer 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | public let language: Language 18 | 19 | public init(language: Language, name: String? = nil) { 20 | self.language = language 21 | self.name = name ?? StemmerFilter.defaultStemmerName(language: language) 22 | } 23 | 24 | public init() { 25 | self.init(language: Language.english) 26 | } 27 | 28 | /// returns stemmer name 29 | internal static func defaultStemmerName(language: Language) -> String { 30 | return "\(StemmerFilter.typeKey.rawValue)_\(language.rawValue)" 31 | } 32 | 33 | // MARK: - Codable 34 | enum CodingKeys: String, CodingKey { 35 | case type 36 | case language = "name" 37 | } 38 | /// :nodoc: 39 | public init(from decoder: Decoder) throws { 40 | 41 | let container = try decoder.container(keyedBy: CodingKeys.self) 42 | 43 | self.language = try container.decode(Language.self, forKey: CodingKeys.language) 44 | self.name = StemmerFilter.defaultStemmerName(language: self.language) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/SynonymFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The synonym token filter allows to easily handle synonyms during the analysis process. Synonyms are configured using a configuration file. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-synonym-tokenfilter.html) 8 | */ 9 | public struct SynonymFilter: TokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.synonym 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let synonyms: [String]? 17 | public let synonymsPath: String? 18 | public let format: Format 19 | public let expand: Bool? 20 | 21 | public enum Format: String, Codable { 22 | case solr 23 | case wordnet 24 | } 25 | 26 | enum CodingKeys: String, CodingKey { 27 | case type 28 | case synonyms 29 | case synonymsPath = "synonyms_path" 30 | case format 31 | case expand 32 | } 33 | 34 | public init(name: String, synonyms: [String], format: Format = .solr, expand: Bool? = nil) { 35 | self.name = name 36 | self.synonyms = synonyms 37 | self.synonymsPath = nil 38 | self.format = format 39 | self.expand = expand 40 | } 41 | 42 | public init(name: String, synonymsPath: String, format: Format = .solr, expand: Bool? = nil) { 43 | self.name = name 44 | self.synonyms = nil 45 | self.synonymsPath = synonymsPath 46 | self.format = format 47 | self.expand = expand 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.synonyms = try container.decodeIfPresent([String].self, forKey: .synonyms) 56 | self.synonymsPath = try container.decodeIfPresent(String.self, forKey: .synonymsPath) 57 | if let format = try container.decodeIfPresent(Format.self, forKey: .format) { 58 | self.format = format 59 | } 60 | else { 61 | self.format = .solr 62 | } 63 | self.expand = try container.decodeIfPresent(Bool.self, forKey: .expand) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/TrimFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The trim token filter trims the whitespace surrounding a token. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-trim-tokenfilter.html) 8 | */ 9 | public struct TrimFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.trim 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Filters/Token/UppercaseFilter.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A token filter of type uppercase that normalizes token text to upper case. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-uppercase-tokenfilter.html) 8 | */ 9 | public struct UppercaseFilter: BasicTokenFilter, BuiltinTokenFilter { 10 | /// :nodoc: 11 | public static var typeKey = TokenFilterType.uppercase 12 | 13 | /// Holds the string that Elasticsearch uses to identify the filter type 14 | public let type = typeKey.rawValue 15 | /// :nodoc: 16 | public let name: String 17 | 18 | public init() { 19 | self.name = self.type 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/IndexMeta.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// :nodoc: 4 | internal struct IndexMeta: Codable { 5 | var `private`: PrivateIndexMeta 6 | var userDefined: [String: String]? 7 | 8 | init() { 9 | self.private = PrivateIndexMeta(version: 1) 10 | } 11 | } 12 | 13 | /// :nodoc: 14 | public struct PrivateIndexMeta: Codable { 15 | let serialVersion: Int 16 | var propertiesHash: String 17 | 18 | init(version: Int) { 19 | self.serialVersion = version 20 | self.propertiesHash = "" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/IndexModifies.swift: -------------------------------------------------------------------------------- 1 | 2 | public protocol IndexModifies { 3 | mutating func modifyAfterReceiving(index: ElasticsearchIndex) 4 | } 5 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/IndexSettings.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | public struct IndexSettings: Codable { 5 | let numberOfShards: Int 6 | let numberOfReplicas: Int 7 | var creationDate: String? = nil 8 | var uuid: String? = nil 9 | var version: Version? = nil 10 | var providedName: String? = nil 11 | 12 | enum CodingKeys: String, CodingKey { 13 | case numberOfShards = "number_of_shards" 14 | case numberOfReplicas = "number_of_replicas" 15 | case creationDate = "creation_date" 16 | case uuid 17 | case version 18 | case providedName = "provided_name" 19 | } 20 | 21 | public init(shards: Int, replicas: Int) { 22 | numberOfShards = shards 23 | numberOfReplicas = replicas 24 | } 25 | 26 | public init(from decoder: Decoder) throws { 27 | let container = try decoder.container(keyedBy: CodingKeys.self) 28 | 29 | numberOfShards = Int(try container.decode(String.self, forKey: .numberOfShards))! 30 | numberOfReplicas = Int(try container.decode(String.self, forKey: .numberOfReplicas))! 31 | creationDate = try container.decodeIfPresent(String.self, forKey: .creationDate) 32 | uuid = try container.decodeIfPresent(String.self, forKey: .uuid) 33 | version = try container.decodeIfPresent(Version.self, forKey: .version) 34 | providedName = try container.decodeIfPresent(String.self, forKey: .providedName) 35 | } 36 | 37 | public struct Version: Codable { 38 | let created: String 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapBinary.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapBinary: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.binary 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let docValues: Bool? 17 | public let store: Bool? 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case type 21 | case docValues = "doc_values" 22 | case store 23 | } 24 | 25 | public init(docValues: Bool? = nil, store: Bool? = nil) { 26 | self.docValues = docValues 27 | self.store = store 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapBoolean.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapBoolean: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.boolean 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let boost: Float? 17 | public let docValues: Bool? 18 | public let index: Bool? 19 | public let nullValue: Bool? 20 | public let store: Bool? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case type 24 | case boost 25 | case docValues = "doc_values" 26 | case index 27 | case nullValue = "null_value" 28 | case store 29 | } 30 | 31 | public init(docValues: Bool? = nil, 32 | index: Bool? = nil, 33 | store: Bool? = nil, 34 | boost: Float? = nil, 35 | nullValue: Bool? = nil) { 36 | 37 | self.boost = boost 38 | self.docValues = docValues 39 | self.index = index 40 | self.nullValue = nullValue 41 | self.store = store 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapByte.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapByte: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.byte 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Int8? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Int8? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapDate.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapDate: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.date 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let boost: Float? 17 | public let docValues: Bool? 18 | public let format: String? 19 | public let locale: String? 20 | public let ignoreMalformed: Bool? 21 | public let index: Bool? 22 | public let nullValue: Bool? 23 | public let store: Bool? 24 | 25 | enum CodingKeys: String, CodingKey { 26 | case type 27 | case boost 28 | case docValues = "doc_values" 29 | case format 30 | case locale 31 | case ignoreMalformed = "ignoreMalformed" 32 | case index 33 | case nullValue = "null_value" 34 | case store 35 | } 36 | 37 | public init(format: String? = nil, 38 | docValues: Bool? = nil, 39 | index: Bool? = nil, 40 | store: Bool? = nil, 41 | boost: Float? = nil, 42 | locale: String? = nil, 43 | ignoreMalformed: Bool? = nil, 44 | nullValue: Bool? = nil) { 45 | 46 | self.boost = boost 47 | self.docValues = docValues 48 | self.format = format 49 | self.locale = locale 50 | self.ignoreMalformed = ignoreMalformed 51 | self.index = index 52 | self.nullValue = nullValue 53 | self.store = store 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapDateRange.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapDateRange: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.dateRange 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let format: String 17 | public let coerce: Bool? 18 | public let boost: Float? 19 | public let index: Bool? 20 | public let store: Bool? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case type 24 | case format 25 | case coerce 26 | case boost 27 | case index 28 | case store 29 | } 30 | 31 | public init(format: String, 32 | index: Bool? = nil, 33 | store: Bool? = nil, 34 | boost: Float? = nil, 35 | coerce: Bool? = nil) { 36 | 37 | self.format = format 38 | self.coerce = coerce 39 | self.boost = boost 40 | self.index = index 41 | self.store = store 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapDouble.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapDouble: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.double 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Double? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Double? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapDoubleRange.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapDoubleRange: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.doubleRange 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let index: Bool? 19 | public let store: Bool? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case coerce 24 | case boost 25 | case index 26 | case store 27 | } 28 | 29 | public init(index: Bool? = nil, 30 | store: Bool? = nil, 31 | boost: Float? = nil, 32 | coerce: Bool? = nil) { 33 | 34 | self.index = index 35 | self.store = store 36 | self.boost = boost 37 | self.coerce = coerce 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapFloat.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapFloat: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.float 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Float? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Float? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapFloatRange.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapFloatRange: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.floatRange 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let index: Bool? 19 | public let store: Bool? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case coerce 24 | case boost 25 | case index 26 | case store 27 | } 28 | 29 | public init(index: Bool? = nil, 30 | store: Bool? = nil, 31 | boost: Float? = nil, 32 | coerce: Bool? = nil) { 33 | 34 | self.index = index 35 | self.store = store 36 | self.boost = boost 37 | self.coerce = coerce 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapGeoPoint.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | 11 | import Foundation 12 | 13 | public struct MapGeoPoint: Mappable { 14 | /// :nodoc: 15 | public static var typeKey = MapType.geoPoint 16 | 17 | /// Holds the string that Elasticsearch uses to identify the mapping type 18 | public let type = typeKey.rawValue 19 | public let ignoreMalformed: Bool? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case ignoreMalformed = "ignore_malformed" 24 | } 25 | 26 | public init(ignoreMalformed: Bool? = nil) { 27 | self.ignoreMalformed = ignoreMalformed 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapHalfFloat.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapHalfFloat: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.halfFloat 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Float? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Float? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapIPAddress.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapIPAddress: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.ipAddress 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let boost: Float? 17 | public let docValues: Bool? 18 | public let index: Bool? 19 | public let nullValue: Bool? 20 | public let store: Bool? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case type 24 | case boost 25 | case docValues = "doc_values" 26 | case index 27 | case nullValue = "null_value" 28 | case store 29 | } 30 | 31 | public init(docValues: Bool? = nil, 32 | index: Bool? = nil, 33 | store: Bool? = nil, 34 | boost: Float? = nil, 35 | nullValue: Bool? = nil) { 36 | 37 | self.boost = boost 38 | self.docValues = docValues 39 | self.index = index 40 | self.nullValue = nullValue 41 | self.store = store 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapInteger.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapInteger: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.integer 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Int32? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Int32? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapIntegerRange.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapIntegerRange: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.integerRange 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let index: Bool? 19 | public let store: Bool? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case coerce 24 | case boost 25 | case index 26 | case store 27 | } 28 | 29 | public init(index: Bool? = nil, 30 | store: Bool? = nil, 31 | boost: Float? = nil, 32 | coerce: Bool? = nil) { 33 | 34 | self.index = index 35 | self.store = store 36 | self.boost = boost 37 | self.coerce = coerce 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapJoin.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapJoin: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.join 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let relations: [String: String] 17 | 18 | enum CodingKeys: String, CodingKey { 19 | case type 20 | case relations 21 | } 22 | 23 | public init(relations: [String: String]) { 24 | self.relations = relations 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapLong.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapLong: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.long 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Int64? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Int64? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapLongRange.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapLongRange: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.longRange 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public var coerce: Bool? 17 | public var boost: Float? 18 | public var index: Bool? 19 | public var store: Bool? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case type 23 | case coerce 24 | case boost 25 | case index 26 | case store 27 | } 28 | 29 | public init(index: Bool? = nil, 30 | store: Bool? = nil, 31 | boost: Float? = nil, 32 | coerce: Bool? = nil) { 33 | 34 | self.index = index 35 | self.store = store 36 | self.boost = boost 37 | self.coerce = coerce 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapPercolator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapPercolator: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.percolator 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | 17 | enum CodingKeys: String, CodingKey { 18 | case type 19 | } 20 | 21 | public init() {} 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapScaledFloat.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapScaledFloat: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.scaledFloat 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Float? 22 | public let store: Bool? 23 | 24 | public var scalingFactor: Int? = 0 25 | 26 | enum CodingKeys: String, CodingKey { 27 | case type 28 | case coerce 29 | case boost 30 | case docValues = "doc_values" 31 | case ignoreMalformed = "ignore_malformed" 32 | case index 33 | case nullValue = "null_value" 34 | case store 35 | case scalingFactor = "scaling_factor" 36 | } 37 | 38 | public init(scalingFactor: Int? = nil, 39 | docValues: Bool? = nil, 40 | index: Bool? = nil, 41 | store: Bool? = nil, 42 | boost: Float? = nil, 43 | coerce: Bool? = nil, 44 | ignoreMalformed: Bool? = nil, 45 | nullValue: Float? = nil) { 46 | 47 | self.scalingFactor = scalingFactor 48 | self.coerce = coerce 49 | self.boost = boost 50 | self.docValues = docValues 51 | self.ignoreMalformed = ignoreMalformed 52 | self.index = index 53 | self.nullValue = nullValue 54 | self.store = store 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapShort.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapShort: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.short 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let coerce: Bool? 17 | public let boost: Float? 18 | public let docValues: Bool? 19 | public let ignoreMalformed: Bool? 20 | public let index: Bool? 21 | public let nullValue: Int16? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case coerce 27 | case boost 28 | case docValues = "doc_values" 29 | case ignoreMalformed = "ignore_malformed" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | boost: Float? = nil, 39 | coerce: Bool? = nil, 40 | ignoreMalformed: Bool? = nil, 41 | nullValue: Int16? = nil) { 42 | 43 | self.coerce = coerce 44 | self.boost = boost 45 | self.docValues = docValues 46 | self.ignoreMalformed = ignoreMalformed 47 | self.index = index 48 | self.nullValue = nullValue 49 | self.store = store 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/MappingTypes/MapTokenCount.swift: -------------------------------------------------------------------------------- 1 | /* 2 | These structs define all of the types that Elasticsearch can store, 3 | how they map to Swift types and allows the user to configure what 4 | the mapping should be like in their index. 5 | 6 | The list of types in Elasticsearch can be found at: 7 | https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html 8 | */ 9 | 10 | public struct MapTokenCount: Mappable { 11 | /// :nodoc: 12 | public static var typeKey = MapType.tokenCount 13 | 14 | /// Holds the string that Elasticsearch uses to identify the mapping type 15 | public let type = typeKey.rawValue 16 | public let analyzer: String? 17 | public let enablePositionIncrements: Bool? 18 | public let boost: Float? 19 | public let docValues: Bool? 20 | public let index: Bool? 21 | public let nullValue: Bool? 22 | public let store: Bool? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case analyzer 27 | case enablePositionIncrements = "enable_position_increments" 28 | case boost 29 | case docValues = "doc_values" 30 | case index 31 | case nullValue = "null_value" 32 | case store 33 | } 34 | 35 | public init(docValues: Bool? = nil, 36 | index: Bool? = nil, 37 | store: Bool? = nil, 38 | analyzer: String? = nil, 39 | enablePositionIncrements: Bool? = nil, 40 | boost: Float? = nil, 41 | nullValue: Bool? = nil) { 42 | 43 | self.docValues = docValues 44 | self.index = index 45 | self.store = store 46 | self.analyzer = analyzer 47 | self.enablePositionIncrements = enablePositionIncrements 48 | self.boost = boost 49 | self.nullValue = nullValue 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Normalizers/CustomNormalizer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | /** 3 | Normalizers are similar to analyzers except that they may only emit a single token. As a consequence, they do not have a tokenizer and only accept a subset of the available char filters and token filters. Only the filters that work on a per-character basis are allowed. For instance a lowercasing filter would be allowed, but not a stemming filter, which needs to look at the keyword as a whole. The current list of filters that can be used in a normalizer is following: ArabicNormalizationFilter, ASCIIFolding, BengaliNormalizationFilter, cjk_width, DecimalDigitFilter, ElisionFilter, GermanNormalizationFilter, HindiNormalizationFilter, IndicNormalizationFilter, lowercase, PersianNormalizationFilter, ScandinavianFoldingFilter, SerbianNormalizationFilter, SoraniNormalizationFilter, uppercase. 4 | 5 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-normalizers.html) 6 | */ 7 | public struct CustomNormalizer: Normalizer { 8 | /// :nodoc: 9 | public static var typeKey = NormalizerType.custom 10 | 11 | /// Holds the string that Elasticsearch uses to identify the normalizer type 12 | public let type = typeKey.rawValue 13 | 14 | public let name: String 15 | public let charFilter: [String]? 16 | public let filter: [String]? 17 | 18 | enum CodingKeys: String, CodingKey { 19 | case type 20 | case charFilter = "char_filter" 21 | case filter 22 | } 23 | 24 | public init(name: String, filter: [String]? = nil, charFilter:[String]? = nil) { 25 | self.name = name 26 | self.filter = filter 27 | self.charFilter = charFilter 28 | } 29 | 30 | /// :nodoc: 31 | public init(from decoder: Decoder) throws { 32 | let container = try decoder.container(keyedBy: CodingKeys.self) 33 | self.name = (decoder.codingPath.last?.stringValue)! 34 | 35 | self.charFilter = try container.decodeIfPresent([String].self, forKey: .charFilter) 36 | self.filter = try container.decodeIfPresent([String].self, forKey: .filter) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Normalizers/Normalizer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// :nodoc: 4 | public protocol Normalizer: Codable { 5 | static var typeKey: NormalizerType { get } 6 | var name: String { get } 7 | } 8 | 9 | /// :nodoc: 10 | public enum NormalizerType: String, Codable { 11 | case custom 12 | 13 | var metatype: Normalizer.Type { 14 | switch self { 15 | case .custom: 16 | return CustomNormalizer.self 17 | } 18 | } 19 | } 20 | 21 | /// :nodoc: 22 | internal struct AnyNormalizer : Codable { 23 | var base: Normalizer 24 | 25 | init(_ base: Normalizer) { 26 | self.base = base 27 | } 28 | 29 | /// :nodoc: 30 | public init(from decoder: Decoder) throws { 31 | let container = try decoder.container(keyedBy: DynamicKey.self) 32 | 33 | let type = try container.decode(NormalizerType.self, forKey: DynamicKey(stringValue: "type")!) 34 | self.base = try type.metatype.init(from: decoder) 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | try base.encode(to: encoder) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/EdgeNGramTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The edge_ngram tokenizer first breaks text down into words whenever it encounters one of a list of specified characters, then it emits N-grams of each word where the start of the N-gram is anchored to the beginning of the word. 6 | 7 | Edge N-Grams are useful for search-as-you-type queries. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html) 10 | */ 11 | public struct EdgeNGramTokenizer: Tokenizer { 12 | /// :nodoc: 13 | public static var typeKey = TokenizerType.edgengram 14 | 15 | public enum CharacterClass: String, Codable { 16 | case letter 17 | case digit 18 | case whitespace 19 | case punctuation 20 | case symbol 21 | } 22 | 23 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 24 | public let type = typeKey.rawValue 25 | public let name: String 26 | public let minGram: Int? 27 | public let maxGram: Int? 28 | public let tokenChars: [CharacterClass]? 29 | 30 | enum CodingKeys: String, CodingKey { 31 | case type 32 | case minGram = "min_gram" 33 | case maxGram = "max_gram" 34 | case tokenChars = "token_chars" 35 | } 36 | 37 | public init(name: String, minGram: Int, maxGram: Int, tokenChars: [CharacterClass]? = nil) { 38 | self.name = name 39 | self.minGram = minGram 40 | self.maxGram = maxGram 41 | self.tokenChars = tokenChars 42 | } 43 | 44 | /// :nodoc: 45 | public init(from decoder: Decoder) throws { 46 | let container = try decoder.container(keyedBy: CodingKeys.self) 47 | self.name = (decoder.codingPath.last?.stringValue)! 48 | 49 | self.minGram = try container.decodeIfPresent(Int.self, forKey: .minGram) 50 | self.maxGram = try container.decodeIfPresent(Int.self, forKey: .maxGram) 51 | self.tokenChars = try container.decodeIfPresent([CharacterClass].self, forKey: .tokenChars) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/KeywordTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The keyword tokenizer is a “noop” tokenizer that accepts whatever text it is given and outputs the exact same text as a single term. It can be combined with token filters to normalise output, e.g. lower-casing email addresses. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-keyword-tokenizer.html) 8 | */ 9 | public struct KeywordTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.keyword 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public var bufferSize: Int? 17 | 18 | let isCustom: Bool 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case bufferSize = "buffer_size" 23 | } 24 | 25 | public init() { 26 | self.name = self.type 27 | self.bufferSize = nil 28 | self.isCustom = false 29 | } 30 | 31 | public init(name: String, bufferSize: Int) { 32 | self.name = name 33 | self.bufferSize = bufferSize 34 | self.isCustom = true 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | if self.isCustom { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(type, forKey: .type) 42 | try container.encode(bufferSize, forKey: .bufferSize) 43 | } 44 | else { 45 | var container = encoder.singleValueContainer() 46 | try container.encode(type) 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.bufferSize = try container.decodeIfPresent(Int.self, forKey: .bufferSize) 56 | self.isCustom = true 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/LetterTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The letter tokenizer breaks text into terms whenever it encounters a character which is not a letter. It does a reasonable job for most European languages, but does a terrible job for some Asian languages, where words are not separated by spaces. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html) 8 | */ 9 | public struct LetterTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.letter 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/LowercaseTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The lowercase tokenizer, like the letter tokenizer breaks text into terms whenever it encounters a character which is not a letter, but it also lowercases all terms. It is functionally equivalent to the letter tokenizer combined with the lowercase token filter, but is more efficient as it performs both steps in a single pass. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenizer.html) 8 | */ 9 | public struct LowercaseTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.lowercase 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/NGramTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The ngram tokenizer first breaks text down into words whenever it encounters one of a list of specified characters, then it emits N-grams of each word of the specified length. 6 | 7 | N-grams are like a sliding window that moves across the word - a continuous sequence of characters of the specified length. They are useful for querying languages that don’t use spaces or that have long compound words, like German. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html) 10 | */ 11 | public struct NGramTokenizer: Tokenizer { 12 | /// :nodoc: 13 | public static var typeKey = TokenizerType.ngram 14 | 15 | public enum CharacterClass: String, Codable { 16 | case letter 17 | case digit 18 | case whitespace 19 | case punctuation 20 | case symbol 21 | } 22 | 23 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 24 | public let type = typeKey.rawValue 25 | public let name: String 26 | public let minGram: Int? 27 | public let maxGram: Int? 28 | public let tokenChars: [CharacterClass]? 29 | 30 | enum CodingKeys: String, CodingKey { 31 | case type 32 | case minGram = "min_gram" 33 | case maxGram = "max_gram" 34 | case tokenChars = "token_chars" 35 | } 36 | 37 | public init(name: String, minGram: Int, maxGram: Int, tokenChars: [CharacterClass]? = nil) { 38 | self.name = name 39 | self.minGram = minGram 40 | self.maxGram = maxGram 41 | self.tokenChars = tokenChars 42 | } 43 | 44 | /// :nodoc: 45 | public init(from decoder: Decoder) throws { 46 | let container = try decoder.container(keyedBy: CodingKeys.self) 47 | self.name = (decoder.codingPath.last?.stringValue)! 48 | 49 | self.minGram = try container.decodeIfPresent(Int.self, forKey: .minGram) 50 | self.maxGram = try container.decodeIfPresent(Int.self, forKey: .maxGram) 51 | self.tokenChars = try container.decodeIfPresent([CharacterClass].self, forKey: .tokenChars) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/PathHierarchyTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The path hierarchy tokenizer takes a hierarchical value like a filesystem path, splits on the path separator, and emits a term for each component in the tree. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pathhierarchy-tokenizer.html) 8 | */ 9 | public struct PathHierarchyTokenizer: Tokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.pathHierarchy 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let delimiter: String? 17 | public let replacement: String? 18 | public let bufferSize: Int? 19 | public let reverse: Bool? 20 | public let skip: Int? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case type 24 | case delimiter 25 | case replacement 26 | case bufferSize = "buffer_size" 27 | case reverse 28 | case skip 29 | } 30 | 31 | public init(name: String, delimiter: String, replacement: String? = nil, bufferSize: Int? = nil, reverse: Bool? = nil, skip: Int? = nil) { 32 | self.name = name 33 | self.delimiter = delimiter 34 | self.replacement = replacement 35 | self.bufferSize = bufferSize 36 | self.reverse = reverse 37 | self.skip = skip 38 | } 39 | 40 | /// :nodoc: 41 | public init(from decoder: Decoder) throws { 42 | let container = try decoder.container(keyedBy: CodingKeys.self) 43 | self.name = (decoder.codingPath.last?.stringValue)! 44 | 45 | self.delimiter = try container.decodeIfPresent(String.self, forKey: .delimiter) 46 | self.replacement = try container.decodeIfPresent(String.self, forKey: .replacement) 47 | self.bufferSize = try container.decodeIfPresent(Int.self, forKey: .bufferSize) 48 | self.reverse = try container.decodeIfPresent(Bool.self, forKey: .reverse) 49 | self.skip = try container.decodeIfPresent(Int.self, forKey: .skip) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/PatternTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The pattern tokenizer uses a regular expression to either split text into terms whenever it matches a word separator, or to capture matching text as terms. 6 | 7 | The default pattern is \W+, which splits text whenever it encounters non-word characters. 8 | 9 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pattern-tokenizer.html) 10 | */ 11 | public struct PatternTokenizer: Tokenizer { 12 | /// :nodoc: 13 | public static var typeKey = TokenizerType.pattern 14 | 15 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 16 | public let type = typeKey.rawValue 17 | public let name: String 18 | public let pattern: String? 19 | public let flags: String? 20 | public let group: Int? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case type 24 | case pattern 25 | case flags 26 | case group 27 | } 28 | 29 | public init(name: String, pattern: String, flags: String? = nil, group: Int? = nil) { 30 | self.name = name 31 | self.pattern = pattern 32 | self.flags = flags 33 | self.group = group 34 | } 35 | 36 | /// :nodoc: 37 | public init(from decoder: Decoder) throws { 38 | let container = try decoder.container(keyedBy: CodingKeys.self) 39 | self.name = (decoder.codingPath.last?.stringValue)! 40 | 41 | self.pattern = try container.decodeIfPresent(String.self, forKey: .pattern) 42 | self.flags = try container.decodeIfPresent(String.self, forKey: .flags) 43 | self.group = try container.decodeIfPresent(Int.self, forKey: .group) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/SimplePatternSplitTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The simple pattern split tokenizer uses a regular expression to split the input into terms at pattern matches. The set of regular expression features it supports is more limited than the pattern tokenizer, but the tokenization is generally faster. 6 | 7 | This tokenizer does not produce terms from the matches themselves. To produce terms from matches using patterns in the same restricted regular expression subset, see the simple_pattern tokenizer. 8 | 9 | This tokenizer uses Lucene regular expressions. For an explanation of the supported features and syntax, see Regular Expression Syntax. 10 | 11 | The default pattern is the empty string, which produces one term containing the full input. This tokenizer should always be configured with a non-default pattern. 12 | 13 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-simplepatternsplit-tokenizer.html) 14 | */ 15 | public struct SimplePatternSplitTokenizer: Tokenizer { 16 | /// :nodoc: 17 | public static var typeKey = TokenizerType.simplePatternSplit 18 | 19 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 20 | public let type = typeKey.rawValue 21 | public let name: String 22 | public let pattern: String? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case pattern 27 | } 28 | 29 | public init(name: String, pattern: String) { 30 | self.name = name 31 | self.pattern = pattern 32 | } 33 | 34 | /// :nodoc: 35 | public init(from decoder: Decoder) throws { 36 | let container = try decoder.container(keyedBy: CodingKeys.self) 37 | self.name = (decoder.codingPath.last?.stringValue)! 38 | 39 | self.pattern = try container.decodeIfPresent(String.self, forKey: .pattern) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/SimplePatternTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The simple pattern tokenizer uses a regular expression to capture matching text as terms. The set of regular expression features it supports is more limited than the pattern tokenizer, but the tokenization is generally faster. 6 | 7 | This tokenizer does not support splitting the input on a pattern match, unlike the pattern tokenizer. To split on pattern matches using the same restricted regular expression subset, see the simple_pattern_split tokenizer. 8 | 9 | This tokenizer uses Lucene regular expressions. For an explanation of the supported features and syntax, see Regular Expression Syntax. 10 | 11 | The default pattern is the empty string, which produces no terms. This tokenizer should always be configured with a non-default pattern. 12 | 13 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-simplepattern-tokenizer.html) 14 | */ 15 | public struct SimplePatternTokenizer: Tokenizer { 16 | /// :nodoc: 17 | public static var typeKey = TokenizerType.simplePattern 18 | 19 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 20 | public let type = typeKey.rawValue 21 | public let name: String 22 | public let pattern: String? 23 | 24 | enum CodingKeys: String, CodingKey { 25 | case type 26 | case pattern 27 | } 28 | 29 | public init(name: String, pattern: String) { 30 | self.name = name 31 | self.pattern = pattern 32 | } 33 | 34 | /// :nodoc: 35 | public init(from decoder: Decoder) throws { 36 | let container = try decoder.container(keyedBy: CodingKeys.self) 37 | self.name = (decoder.codingPath.last?.stringValue)! 38 | 39 | self.pattern = try container.decodeIfPresent(String.self, forKey: .pattern) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/StandardTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The standard tokenizer provides grammar based tokenization (based on the Unicode Text Segmentation algorithm, as specified in Unicode Standard Annex #29) and works well for most languages. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html) 8 | */ 9 | public struct StandardTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.standard 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let maxTokenLength: Int? 17 | 18 | let isCustom: Bool 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case maxTokenLength = "max_token_length" 23 | } 24 | 25 | public init() { 26 | self.name = type 27 | self.maxTokenLength = nil 28 | self.isCustom = false 29 | } 30 | 31 | public init(name: String, maxTokenLength: Int) { 32 | self.name = name 33 | self.maxTokenLength = maxTokenLength 34 | self.isCustom = true 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | if self.isCustom { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(type, forKey: .type) 42 | try container.encode(maxTokenLength, forKey: .maxTokenLength) 43 | } 44 | else { 45 | var container = encoder.singleValueContainer() 46 | try container.encode(type) 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.maxTokenLength = try container.decodeIfPresent(Int.self, forKey: .maxTokenLength) 56 | self.isCustom = true 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/ThaiTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The thai tokenizer segments Thai text into words, using the Thai segmentation algorithm included with Java. Text in other languages in general will be treated the same as the standard tokenizer. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-thai-tokenizer.html) 8 | */ 9 | public struct ThaiTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.thai 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | 17 | public init() { 18 | self.name = type 19 | } 20 | 21 | /// :nodoc: 22 | public func encode(to encoder: Encoder) throws { 23 | var container = encoder.singleValueContainer() 24 | try container.encode(type) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/UAXURLEmailTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The uax url email tokenizer is like the standard tokenizer except that it recognises URLs and email addresses as single tokens. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-uaxurlemail-tokenizer.html) 8 | */ 9 | public struct UAXURLEmailTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.UAXURLEmail 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let maxTokenLength: Int? 17 | 18 | let isCustom: Bool 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case maxTokenLength = "max_token_length" 23 | } 24 | 25 | public init() { 26 | self.name = type 27 | self.maxTokenLength = nil 28 | self.isCustom = false 29 | } 30 | 31 | public init(name: String, maxTokenLength: Int) { 32 | self.name = name 33 | self.maxTokenLength = maxTokenLength 34 | self.isCustom = true 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | if self.isCustom { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(type, forKey: .type) 42 | try container.encode(maxTokenLength, forKey: .maxTokenLength) 43 | } 44 | else { 45 | var container = encoder.singleValueContainer() 46 | try container.encode(type) 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.maxTokenLength = try container.decodeIfPresent(Int.self, forKey: .maxTokenLength) 56 | self.isCustom = true 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Index/Tokenizers/WhitespaceTokenizer.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | The whitespace tokenizer breaks text into terms whenever it encounters a whitespace character. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-whitespace-tokenizer.html) 8 | */ 9 | public struct WhitespaceTokenizer: Tokenizer, BultinTokenizer { 10 | /// :nodoc: 11 | public static var typeKey = TokenizerType.whitespace 12 | 13 | /// Holds the string that Elasticsearch uses to identify the tokenizer type 14 | public let type = typeKey.rawValue 15 | public let name: String 16 | public let maxTokenLength: Int? 17 | 18 | let isCustom: Bool 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case type 22 | case maxTokenLength = "max_token_length" 23 | } 24 | 25 | public init() { 26 | self.name = type 27 | self.maxTokenLength = nil 28 | self.isCustom = false 29 | } 30 | 31 | public init(name: String, maxTokenLength: Int) { 32 | self.name = name 33 | self.maxTokenLength = maxTokenLength 34 | self.isCustom = true 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | if self.isCustom { 40 | var container = encoder.container(keyedBy: CodingKeys.self) 41 | try container.encode(type, forKey: .type) 42 | try container.encode(maxTokenLength, forKey: .maxTokenLength) 43 | } 44 | else { 45 | var container = encoder.singleValueContainer() 46 | try container.encode(type) 47 | } 48 | } 49 | 50 | /// :nodoc: 51 | public init(from decoder: Decoder) throws { 52 | let container = try decoder.container(keyedBy: CodingKeys.self) 53 | self.name = (decoder.codingPath.last?.stringValue)! 54 | 55 | self.maxTokenLength = try container.decodeIfPresent(Int.self, forKey: .maxTokenLength) 56 | self.isCustom = true 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationDateHistogramResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationDateHistogramResponse: AggregationResponse { 4 | public var name: String 5 | public let buckets: [AggregationDateBucket] 6 | 7 | enum CodingKeys: String, CodingKey { 8 | case buckets 9 | } 10 | 11 | public init(from decoder: Decoder) throws { 12 | let container = try decoder.container(keyedBy: CodingKeys.self) 13 | self.name = (decoder.codingPath.last?.stringValue)! 14 | 15 | self.buckets = try container.decode([AggregationDateBucket].self, forKey: .buckets) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationExtendedStatsResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationExtendedStatsResponse: AggregationResponse { 4 | public var name: String 5 | public let count: Int 6 | public let min: Float 7 | public let max: Float 8 | public let avg: Float 9 | public let sum: Float 10 | public let sumOfSquares: Float 11 | public let variance: Float 12 | public let stdDeviation: Float 13 | public let stdDeviationBounds: StandardDeviationBounds 14 | 15 | public struct StandardDeviationBounds: Decodable { 16 | public let upper: Float 17 | public let lower: Float 18 | } 19 | 20 | enum CodingKeys: String, CodingKey { 21 | case count 22 | case min 23 | case max 24 | case avg 25 | case sum 26 | case sumOfSquares = "sum_of_squares" 27 | case variance 28 | case stdDeviation = "std_deviation" 29 | case stdDeviationBounds = "std_deviation_bounds" 30 | } 31 | 32 | public init(from decoder: Decoder) throws { 33 | let container = try decoder.container(keyedBy: CodingKeys.self) 34 | self.name = (decoder.codingPath.last?.stringValue)! 35 | 36 | self.count = try container.decode(Int.self, forKey: .count) 37 | self.min = try container.decode(Float.self, forKey: .min) 38 | self.max = try container.decode(Float.self, forKey: .max) 39 | self.avg = try container.decode(Float.self, forKey: .avg) 40 | self.sum = try container.decode(Float.self, forKey: .sum) 41 | self.sumOfSquares = try container.decode(Float.self, forKey: .sumOfSquares) 42 | self.variance = try container.decode(Float.self, forKey: .variance) 43 | self.stdDeviation = try container.decode(Float.self, forKey: .stdDeviation) 44 | self.stdDeviationBounds = try container.decode(StandardDeviationBounds.self, forKey: .stdDeviationBounds) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationGeoBoundsResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationGeoBoundsResponse: AggregationResponse { 4 | public var name: String 5 | public let bounds: BoundsContainer 6 | 7 | public struct BoundsContainer: Decodable { 8 | public let topLeft: BoundsPoint 9 | public let bottomRight: BoundsPoint 10 | } 11 | 12 | public struct BoundsPoint: Decodable { 13 | public let lat: Float 14 | public let lon: Float 15 | } 16 | 17 | enum CodingKeys: String, CodingKey { 18 | case bounds 19 | } 20 | 21 | public init(from decoder: Decoder) throws { 22 | let container = try decoder.container(keyedBy: CodingKeys.self) 23 | self.name = (decoder.codingPath.last?.stringValue)! 24 | 25 | self.bounds = try container.decode(BoundsContainer.self, forKey: .bounds) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationGeoCentroidResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationGeoCentroidResponse: AggregationResponse { 4 | public var name: String 5 | public let location: BoundsPoint 6 | public let count: Int 7 | 8 | public struct BoundsPoint: Decodable { 9 | public let lat: Float 10 | public let lon: Float 11 | } 12 | 13 | enum CodingKeys: String, CodingKey { 14 | case location 15 | case count 16 | } 17 | 18 | public init(from decoder: Decoder) throws { 19 | let container = try decoder.container(keyedBy: CodingKeys.self) 20 | self.name = (decoder.codingPath.last?.stringValue)! 21 | 22 | self.location = try container.decode(BoundsPoint.self, forKey: .location) 23 | self.count = try container.decode(Int.self, forKey: .count) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationHistogramResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationHistogramResponse: AggregationResponse { 4 | public var name: String 5 | public let buckets: [AggregationIntBucket] 6 | 7 | enum CodingKeys: String, CodingKey { 8 | case buckets 9 | } 10 | 11 | public init(from decoder: Decoder) throws { 12 | let container = try decoder.container(keyedBy: CodingKeys.self) 13 | self.name = (decoder.codingPath.last?.stringValue)! 14 | 15 | self.buckets = try container.decode([AggregationIntBucket].self, forKey: .buckets) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationSingleValueResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationSingleValueResponse: AggregationResponse { 4 | public var name: String 5 | public let value: Float 6 | 7 | enum CodingKeys: String, CodingKey { 8 | case value 9 | } 10 | 11 | public init(from decoder: Decoder) throws { 12 | let container = try decoder.container(keyedBy: CodingKeys.self) 13 | self.name = (decoder.codingPath.last?.stringValue)! 14 | 15 | self.value = try container.decode(Float.self, forKey: .value) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationStatsResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationStatsResponse: AggregationResponse { 4 | public var name: String 5 | public let count: Int 6 | public let min: Float 7 | public let max: Float 8 | public let avg: Float 9 | public let sum: Float 10 | 11 | enum CodingKeys: String, CodingKey { 12 | case count 13 | case min 14 | case max 15 | case avg 16 | case sum 17 | } 18 | 19 | public init(from decoder: Decoder) throws { 20 | let container = try decoder.container(keyedBy: CodingKeys.self) 21 | self.name = (decoder.codingPath.last?.stringValue)! 22 | 23 | self.count = try container.decode(Int.self, forKey: .count) 24 | self.min = try container.decode(Float.self, forKey: .min) 25 | self.max = try container.decode(Float.self, forKey: .max) 26 | self.avg = try container.decode(Float.self, forKey: .avg) 27 | self.sum = try container.decode(Float.self, forKey: .sum) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AggregationTermsResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct AggregationTermsResponse: AggregationResponse { 4 | public var name: String 5 | public let docCountErrorUpperBound: Int 6 | public let sumOtherDocCount: Int 7 | public let buckets: [AggregationBucket] 8 | 9 | enum CodingKeys: String, CodingKey { 10 | case docCountErrorUpperBound = "doc_count_error_upper_bound" 11 | case sumOtherDocCount = "sum_other_doc_count" 12 | case buckets 13 | } 14 | 15 | public init(from decoder: Decoder) throws { 16 | let container = try decoder.container(keyedBy: CodingKeys.self) 17 | self.name = (decoder.codingPath.last?.stringValue)! 18 | 19 | self.docCountErrorUpperBound = try container.decode(Int.self, forKey: .docCountErrorUpperBound) 20 | self.sumOtherDocCount = try container.decode(Int.self, forKey: .sumOtherDocCount) 21 | self.buckets = try container.decode([AggregationBucket].self, forKey: .buckets) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/AnyAggregationResponse.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | internal struct AnyAggregationResponse : Decodable { 5 | public var base: AggregationResponse? 6 | 7 | init(_ base: AggregationResponse) { 8 | self.base = base 9 | } 10 | 11 | private enum CodingKeys : CodingKey { 12 | case base 13 | } 14 | 15 | public init(from decoder: Decoder) throws { 16 | let aggName = (decoder.codingPath.last?.stringValue)! 17 | self.base = try decoder.aggregationResponseType(forAggregationName: aggName, docType: T.self) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/DocResponse.swift: -------------------------------------------------------------------------------- 1 | 2 | public struct DocResponse: Decodable { 3 | public let index :String 4 | public let type :String 5 | public let id :String 6 | public let version :Int 7 | public var source :T 8 | public var routing :String? = nil 9 | 10 | enum CodingKeys: String, CodingKey { 11 | case index = "_index" 12 | case type = "_type" 13 | case id = "_id" 14 | case version = "_version" 15 | case source = "_source" 16 | } 17 | 18 | public init(from decoder: Decoder) throws { 19 | let container = try decoder.container(keyedBy: CodingKeys.self) 20 | self.index = try container.decode(String.self, forKey: .index) 21 | self.type = try container.decode(String.self, forKey: .type) 22 | self.id = try container.decode(String.self, forKey: .id) 23 | self.version = try container.decode(Int.self, forKey: .version) 24 | var source = try container.decode(T.self, forKey: .source) 25 | if var settableIDSource = source as? SettableID { 26 | settableIDSource.setID(self.id) 27 | source = settableIDSource as! T 28 | } 29 | 30 | self.source = source 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/IndexResponse.swift: -------------------------------------------------------------------------------- 1 | public struct IndexResponse: Codable { 2 | public let shards :Shards 3 | public let index :String 4 | public let type :String 5 | public let id :String 6 | public let version :Int 7 | public let result :ResultType 8 | public let seqNo: Int? = nil 9 | public let primaryTerm: Int? = nil 10 | // public let routing :String? 11 | 12 | public struct Shards: Codable { 13 | public let total: Int 14 | public let successful: Int 15 | public let failed: Int 16 | public let skipped: Int? 17 | } 18 | 19 | public enum ResultType: String, Codable { 20 | case created = "created" 21 | case updated = "updated" 22 | case deleted = "deleted" 23 | case notFound = "not_found" 24 | case noop = "noop" 25 | } 26 | 27 | enum CodingKeys: String, CodingKey { 28 | case shards = "_shards" 29 | case index = "_index" 30 | case type = "_type" 31 | case id = "_id" 32 | case version = "_version" 33 | case result 34 | case seqNo = "_seq_no" 35 | case primaryTerm = "_primary_term" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/Response/SuggestResponse.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SuggestResponse: Decodable { 4 | public let took: Int 5 | public let timedOut: Bool 6 | public let shards: Shards 7 | public let hits: HitsContainer? 8 | public let suggest: [String: [SuggestResult]] 9 | 10 | public var suggestions: [String] { 11 | return suggest.values 12 | .flatMap { $0 } 13 | .flatMap { $0.options } 14 | .compactMap { $0.text } 15 | } 16 | 17 | public struct Shards: Decodable { 18 | public let total: Int 19 | public let successful: Int 20 | public let skipped: Int 21 | public let failed: Int 22 | } 23 | 24 | public struct HitsContainer: Decodable { 25 | public let total: Int 26 | public let maxScore: Decimal? 27 | } 28 | 29 | public struct SuggestResult: Decodable { 30 | public let text: String 31 | public let offset: Int 32 | public let length: Int 33 | public let options: [SuggestOption] 34 | } 35 | 36 | public struct SuggestOption: Decodable { 37 | public let id: String 38 | public let text: String 39 | 40 | enum CodingKeys: String, CodingKey { 41 | case id = "_id" 42 | case text 43 | } 44 | } 45 | 46 | enum CodingKeys: String, CodingKey { 47 | case took 48 | case timedOut = "timed_out" 49 | case shards = "_shards" 50 | case hits 51 | case suggest 52 | } 53 | 54 | public init(from decoder: Decoder) throws { 55 | let container = try decoder.container(keyedBy: CodingKeys.self) 56 | 57 | self.took = try container.decode(Int.self, forKey: .took) 58 | self.timedOut = try container.decode(Bool.self, forKey: .timedOut) 59 | self.shards = try container.decode(Shards.self, forKey: .shards) 60 | self.hits = try container.decode(HitsContainer.self, forKey: .hits) 61 | self.suggest = try container.decode([String: [SuggestResult]].self, forKey: .suggest) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Model/SettableID.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | When fetching a document either by id or via a search query, 5 | the model that is populated with the data can implement this 6 | method to have the id for the document set. 7 | 8 | This is necessary due to the fact that Elasticsearch stores 9 | the id for a document outside of the document itself. 10 | */ 11 | public protocol SettableID { 12 | /// Called when the model object is created via fetching by id or via a search result. 13 | /// 14 | /// - Parameter id: The id of the document that can then be set to whatever the id property is. 15 | mutating func setID(_ id: String) 16 | } 17 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Aggregation/Aggregation.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /// :nodoc: 5 | public protocol Aggregation: Encodable { 6 | static var typeKey: AggregationResponseMap { get } 7 | 8 | var name: String { get set } 9 | var aggs: [Aggregation]? { get set } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Aggregation/AnyAggregation.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /// :nodoc: 5 | public enum AggregationResponseMap : String, Encodable { 6 | 7 | case avg 8 | case cardinality 9 | case extendedStats = "extended_stats" 10 | case geoBounds = "geo_bounds" 11 | case geoCentroid = "geo_centroid" 12 | case max 13 | case min 14 | case stats 15 | case sum 16 | case topHits = "top_hits" 17 | case valueCount = "value_count" 18 | case terms 19 | case dateHistogram 20 | case histogram 21 | 22 | func metatype(docType: T.Type) -> AggregationResponse.Type? { 23 | switch self { 24 | case .avg: 25 | return AggregationSingleValueResponse.self 26 | case .cardinality: 27 | return AggregationSingleValueResponse.self 28 | case .extendedStats: 29 | return AggregationExtendedStatsResponse.self 30 | case .geoBounds: 31 | return AggregationGeoBoundsResponse.self 32 | case .geoCentroid: 33 | return AggregationGeoCentroidResponse.self 34 | case .max: 35 | return AggregationSingleValueResponse.self 36 | case .min: 37 | return AggregationSingleValueResponse.self 38 | case .stats: 39 | return AggregationStatsResponse.self 40 | case .sum: 41 | return AggregationSingleValueResponse.self 42 | case .topHits: 43 | return nil 44 | case .valueCount: 45 | return AggregationSingleValueResponse.self 46 | case .terms: 47 | return AggregationTermsResponse.self 48 | case .dateHistogram: 49 | return AggregationDateHistogramResponse.self 50 | case .histogram: 51 | return AggregationHistogramResponse.self 52 | } 53 | } 54 | } 55 | 56 | internal struct AnyAggregation : Encodable { 57 | public var base: Aggregation 58 | 59 | init(_ base: Aggregation) { 60 | self.base = base 61 | } 62 | 63 | private enum CodingKeys : CodingKey { 64 | case type 65 | case base 66 | } 67 | 68 | public func encode(to encoder: Encoder) throws { 69 | try base.encode(to: encoder) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Aggregation/MetricsAggregations/GeoCentroidAggregation.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | /** 5 | A metric aggregation that computes the weighted centroid from all coordinate 6 | values for a Geo-point datatype field. 7 | 8 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-geocentroid-aggregation.html) 9 | */ 10 | public struct GeoCentroidAggregation: Aggregation { 11 | public var aggs: [Aggregation]? 12 | 13 | /// :nodoc: 14 | public static var typeKey = AggregationResponseMap.geoCentroid 15 | 16 | /// :nodoc: 17 | public var name: String 18 | 19 | /// :nodoc: 20 | public let field: String? 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case field 24 | case aggs 25 | } 26 | 27 | /// Creates a [geo_point](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-metrics-geocentroid-aggregation.html) aggregation 28 | /// 29 | /// - Parameters: 30 | /// - name: The aggregation name 31 | /// - field: The field to perform the aggregation over 32 | public init(name: String, field: String, aggs: [Aggregation]? = nil) { 33 | self.name = name 34 | self.field = field 35 | self.aggs = aggs 36 | } 37 | 38 | /// :nodoc: 39 | public func encode(to encoder: Encoder) throws { 40 | var container = encoder.container(keyedBy: DynamicKey.self) 41 | var valuesContainer = container.nestedContainer(keyedBy: CodingKeys.self, forKey: DynamicKey(stringValue: type(of: self).typeKey.rawValue)!) 42 | try valuesContainer.encode(field, forKey: .field) 43 | if aggs != nil { 44 | if aggs != nil { 45 | if aggs != nil && aggs!.count > 0 { 46 | var aggContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: DynamicKey(stringValue: "aggs")!) 47 | for agg in aggs! { 48 | try aggContainer.encode(AnyAggregation(agg), forKey: DynamicKey(stringValue: agg.name)!) 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Decoder+AggregationUserInfo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension JSONDecoder { 4 | internal static let elasticAggs = CodingUserInfoKey(rawValue: "com.elastic.swift.aggs")! 5 | internal static let elasticAnalysis = CodingUserInfoKey(rawValue: "com.elastic.swift.analysis")! 6 | 7 | internal func userInfo(fromAggregations aggregations: [Aggregation]) { 8 | var aggNameMap = [String: Aggregation]() 9 | 10 | for agg in aggregations { 11 | aggNameMap[agg.name] = agg 12 | } 13 | self.userInfo = [JSONDecoder.elasticAggs: aggNameMap] 14 | } 15 | 16 | internal func userInfo(analysis: Analysis) { 17 | self.userInfo = [JSONDecoder.elasticAnalysis: analysis] 18 | } 19 | } 20 | 21 | extension Decoder { 22 | internal func aggregationResponseType(forAggregationName name: String, docType: T.Type) throws -> AggregationResponse? { 23 | let aggDefinitionMap = self.userInfo[JSONDecoder.elasticAggs] as! [String: Aggregation] 24 | 25 | if let defintion = aggDefinitionMap[name] { 26 | if let responseType = AggregationResponseMap(rawValue: type(of: defintion).typeKey.rawValue), 27 | let metatype = responseType.metatype(docType: docType) { 28 | return try metatype.init(from: self) 29 | } 30 | } 31 | 32 | return nil 33 | } 34 | 35 | internal func aggregationDefinition(forAggregationName name: String) throws -> Aggregation? { 36 | let aggDefinitionMap = self.userInfo[JSONDecoder.elasticAggs] as! [String: Aggregation] 37 | return aggDefinitionMap[name] 38 | } 39 | 40 | internal func analysis() -> Analysis? { 41 | return self.userInfo[JSONDecoder.elasticAnalysis] as? Analysis 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/CommonTerms.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The common terms query is a modern alternative to stopwords which improves the 5 | precision and recall of search results (by taking stopwords into account), 6 | without sacrificing performance. 7 | 8 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-common-terms-query.html) 9 | */ 10 | public struct CommonTerms: QueryElement { 11 | /// :nodoc: 12 | public static var typeKey = QueryElementMap.commonTerms 13 | 14 | public let field: String 15 | public let query: String 16 | public let cutoffFrequency: Float 17 | public let lowFreqOperator: Operator? 18 | public let minimumShouldMatch: Int? 19 | 20 | public init(field: String, query: String, cutoffFrequency: Float, lowFreqOperator: Operator?, minimumShouldMatch: Int?) { 21 | self.field = field 22 | self.query = query 23 | self.cutoffFrequency = cutoffFrequency 24 | self.lowFreqOperator = lowFreqOperator 25 | self.minimumShouldMatch = minimumShouldMatch 26 | } 27 | 28 | private struct Inner: Codable { 29 | let query: String 30 | let cutoffFrequency: Float 31 | let lowFreqOperator: Operator? 32 | let minimumShouldMatch: Int? 33 | } 34 | 35 | /// :nodoc: 36 | public func encode(to encoder: Encoder) throws { 37 | var container = encoder.container(keyedBy: DynamicKey.self) 38 | 39 | let inner = CommonTerms.Inner(query: self.query, cutoffFrequency: self.cutoffFrequency, lowFreqOperator: self.lowFreqOperator, minimumShouldMatch: self.minimumShouldMatch) 40 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 41 | } 42 | 43 | /// :nodoc: 44 | public init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: DynamicKey.self) 46 | let key = container.allKeys.first 47 | self.field = key!.stringValue 48 | 49 | let inner = try container.decode(CommonTerms.Inner.self, forKey: key!) 50 | self.query = inner.query 51 | self.cutoffFrequency = inner.cutoffFrequency 52 | self.lowFreqOperator = inner.lowFreqOperator 53 | self.minimumShouldMatch = inner.minimumShouldMatch 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Exists.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Returns documents that have at least one non-null value in the original field. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html) 7 | */ 8 | public struct Exists: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.exists 11 | 12 | public let field: String 13 | 14 | public init(field: String) { 15 | self.field = field 16 | } 17 | 18 | enum CodingKeys: String, CodingKey { 19 | case field 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Geo/GeoHelpers.swift: -------------------------------------------------------------------------------- 1 | 2 | public enum GeoValidationMethod: String, Codable { 3 | case strict = "STRICT" 4 | case coerce = "COERCE" 5 | case ignoreMalformed = "IGNORE_MALFORMED" 6 | } 7 | 8 | public struct GeoPoint: Codable { 9 | public let lat: Float? 10 | public let lon: Float? 11 | public let geoHash: String? 12 | 13 | enum CodingKeys: String, CodingKey { 14 | case lat 15 | case lon 16 | } 17 | 18 | public init(lat: Float, lon: Float) { 19 | self.lat = lat 20 | self.lon = lon 21 | self.geoHash = nil 22 | } 23 | 24 | public init(geoHash: String) { 25 | self.lat = nil 26 | self.lon = nil 27 | self.geoHash = geoHash 28 | } 29 | 30 | /// :nodoc: 31 | public func encode(to encoder: Encoder) throws { 32 | if geoHash != nil { 33 | var container = encoder.singleValueContainer() 34 | try container.encode(self.geoHash) 35 | } 36 | else { 37 | var container = encoder.container(keyedBy: CodingKeys.self) 38 | try container.encode(self.lat, forKey: .lat) 39 | try container.encode(self.lon, forKey: .lon) 40 | } 41 | } 42 | 43 | /// :nodoc: 44 | public init(from decoder: Decoder) throws { 45 | var lat: Float? 46 | var lon: Float? 47 | var geoHash: String? 48 | do { 49 | let container = try decoder.container(keyedBy: CodingKeys.self) 50 | lat = try container.decode(Float.self, forKey: .lat) 51 | lon = try container.decode(Float.self, forKey: .lon) 52 | geoHash = nil 53 | } 54 | catch { 55 | let container = try decoder.singleValueContainer() 56 | geoHash = try container.decode(String.self) 57 | lat = nil 58 | lon = nil 59 | } 60 | 61 | self.lat = lat 62 | self.lon = lon 63 | self.geoHash = geoHash 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Geo/GeoPolygon.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A query allowing to define scripts as queries. They are typically used in a filter context. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-script-query.html) 7 | */ 8 | public struct GeoPolygon: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.geoPolygon 11 | 12 | public let field: String 13 | public let points: [GeoPoint] 14 | public let name: String? 15 | public let validationMethod: GeoValidationMethod? 16 | 17 | enum CodingKeys: String, CodingKey { 18 | case points 19 | case name = "_name" 20 | case validationMethod 21 | } 22 | 23 | public init(field: String, points: [GeoPoint], name: String? = nil, validationMethod: GeoValidationMethod? = nil) { 24 | self.field = field 25 | self.points = points 26 | self.name = name 27 | self.validationMethod = validationMethod 28 | } 29 | 30 | private struct Inner: Codable { 31 | let points: [GeoPoint] 32 | let name: String? 33 | let validationMethod: GeoValidationMethod? 34 | } 35 | 36 | /// :nodoc: 37 | public func encode(to encoder: Encoder) throws { 38 | var container = encoder.container(keyedBy: DynamicKey.self) 39 | 40 | let inner = GeoPolygon.Inner(points: self.points, name: self.name, validationMethod: self.validationMethod) 41 | try container.encode(inner, forKey: DynamicKey(stringValue: self.field)!) 42 | } 43 | 44 | /// :nodoc: 45 | public init(from decoder: Decoder) throws { 46 | let container = try decoder.container(keyedBy: DynamicKey.self) 47 | let field = container.allKeys.first 48 | self.field = field!.stringValue 49 | 50 | let inner = try container.decode(GeoPolygon.Inner.self, forKey: field!) 51 | self.points = inner.points 52 | self.name = inner.name 53 | self.validationMethod = inner.validationMethod 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/IDs.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Filters documents that only have the provided ids. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html) 7 | */ 8 | public struct IDs: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.ids 11 | 12 | public let values: [String] 13 | 14 | public init(_ values: [String]) { 15 | self.values = values 16 | } 17 | 18 | enum CodingKeys: String, CodingKey { 19 | case values 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/MatchAll.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The most simple query, which matches all documents, giving them all a score of 1.0 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-match-all-query.html) 7 | */ 8 | public struct MatchAll: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.matchAll 11 | 12 | public init() {} 13 | 14 | /// :nodoc: 15 | public func encode(to encoder: Encoder) throws {} 16 | 17 | /// :nodoc: 18 | public init(from decoder: Decoder) throws {} 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/MatchNone.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | This is the inverse of the `MatchAll` query, which matches no documents. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-match-all-query.html#query-dsl-match-none-query) 7 | */ 8 | public struct MatchNone: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.matchNone 11 | 12 | public init() {} 13 | 14 | /// :nodoc: 15 | public func encode(to encoder: Encoder) throws {} 16 | 17 | /// :nodoc: 18 | public init(from decoder: Decoder) throws {} 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/MatchPhrase.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The `MatchPhrase` query analyzes the text and creates a phrase query out of the analyzed text. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-match-query-phrase.html) 7 | */ 8 | public struct MatchPhrase: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.matchPhrase 11 | 12 | public let field: String 13 | public let query: String 14 | public let analyzer: String? 15 | public let boost: Decimal? 16 | 17 | public init(field: String, query: String, analyzer: String? = nil, boost: Decimal? = nil) { 18 | self.field = field 19 | self.query = query 20 | self.analyzer = analyzer 21 | self.boost = boost 22 | } 23 | 24 | private struct Inner: Codable { 25 | let query: String 26 | let analyzer: String? 27 | let boost: Decimal? 28 | } 29 | 30 | /// :nodoc: 31 | public func encode(to encoder: Encoder) throws { 32 | var container = encoder.container(keyedBy: DynamicKey.self) 33 | 34 | let inner = MatchPhrase.Inner(query: self.query, analyzer: self.analyzer, boost: self.boost) 35 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 36 | } 37 | 38 | /// :nodoc: 39 | public init(from decoder: Decoder) throws { 40 | let container = try decoder.container(keyedBy: DynamicKey.self) 41 | let key = container.allKeys.first 42 | self.field = key!.stringValue 43 | 44 | let inner = try container.decode(MatchPhrase.Inner.self, forKey: key!) 45 | self.query = inner.query 46 | self.analyzer = inner.analyzer 47 | self.boost = inner.boost 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/MatchPhrasePrefix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The `MatchPhrasePrefix` is the same as match_phrase, except that it allows for prefix matches on the last term in the text. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-match-query-phrase-prefix.html) 7 | */ 8 | public struct MatchPhrasePrefix: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.matchPhrasePrefix 11 | 12 | public let field: String 13 | public let query: String 14 | public let analyzer: String? 15 | public let maxExpansions: Int? 16 | public let boost: Decimal? 17 | 18 | public init(field: String, query: String, analyzer: String? = nil, maxExpansions: Int? = nil, boost: Decimal? = nil) { 19 | self.field = field 20 | self.query = query 21 | self.analyzer = analyzer 22 | self.maxExpansions = maxExpansions 23 | self.boost = boost 24 | } 25 | 26 | private struct Inner: Codable { 27 | let query: String 28 | let analyzer: String? 29 | let maxExpansions: Int? 30 | let boost: Decimal? 31 | } 32 | 33 | /// :nodoc: 34 | public func encode(to encoder: Encoder) throws { 35 | var container = encoder.container(keyedBy: DynamicKey.self) 36 | 37 | let inner = MatchPhrasePrefix.Inner(query: self.query, analyzer: self.analyzer, maxExpansions: self.maxExpansions, boost: self.boost) 38 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 39 | } 40 | 41 | /// :nodoc: 42 | public init(from decoder: Decoder) throws { 43 | let container = try decoder.container(keyedBy: DynamicKey.self) 44 | let key = container.allKeys.first 45 | self.field = key!.stringValue 46 | 47 | let inner = try container.decode(MatchPhrasePrefix.Inner.self, forKey: key!) 48 | self.query = inner.query 49 | self.analyzer = inner.analyzer 50 | self.maxExpansions = inner.maxExpansions 51 | self.boost = inner.boost 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/MultiMatch.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The `MultiMatch` query builds on the `MatchQuery` to allow multi-field queries. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-multi-match-query.html) 7 | */ 8 | public struct MultiMatch: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.multiMatch 11 | 12 | public let value: String 13 | public let fields: [String] 14 | public let type: Kind? 15 | public let fuzziness: Int? 16 | public let tieBreaker: Decimal? 17 | 18 | public init( 19 | value: String, 20 | fields: [String], 21 | type: Kind? = nil, 22 | fuzziness: Int? = nil, 23 | tieBreaker: Decimal? = nil 24 | ) { 25 | self.value = value 26 | self.fields = fields 27 | self.type = type 28 | self.fuzziness = fuzziness 29 | self.tieBreaker = tieBreaker 30 | } 31 | 32 | public enum Kind: String, Codable { 33 | case bestFields = "best_fields" 34 | case mostFields = "most_fields" 35 | case crossFields = "cross_fields" 36 | case phrase 37 | case phrasePrefix = "phrase_prefix" 38 | } 39 | 40 | enum CodingKeys: String, CodingKey { 41 | case value = "query" 42 | case fields 43 | case type 44 | case fuzziness 45 | case tieBreaker = "tie_breaker" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Nested.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Nested.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | Filters documents that have fields that match any of the provided terms (not analyzed). 12 | 13 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html) 14 | */ 15 | public struct Nested: QueryElement { 16 | /// :nodoc: 17 | public static var typeKey = QueryElementMap.nested 18 | 19 | public let path: String 20 | public let scoreMode: String? 21 | public let query: QueryElement 22 | 23 | public init(path: String, scoreMode: String?, query: QueryElement) { 24 | self.path = path 25 | self.scoreMode = scoreMode 26 | self.query = query 27 | } 28 | 29 | private enum CodingKeys: String, CodingKey { 30 | case path 31 | case query 32 | case scoreMode = "score_mode" 33 | 34 | } 35 | 36 | /// :nodoc: 37 | public func encode(to encoder: Encoder) throws { 38 | var container = encoder.container(keyedBy: CodingKeys.self) 39 | try container.encodeIfPresent(path, forKey: .path) 40 | try container.encodeIfPresent(scoreMode, forKey: .scoreMode) 41 | // Encode the query 42 | var queryContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .query) 43 | try queryContainer.encode(AnyQueryElement(query), forKey: DynamicKey(stringValue: type(of: query).typeKey.rawValue)!) 44 | } 45 | 46 | /// :nodoc: 47 | public init(from decoder: Decoder) throws { 48 | let container = try decoder.container(keyedBy: CodingKeys.self) 49 | self.path = try container.decode(String.self, forKey: .path) 50 | self.scoreMode = try container.decodeIfPresent(String.self, forKey: .scoreMode) 51 | self.query = try container.decode(AnyQueryElement.self, forKey: .query).base 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Prefix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Matches documents that have fields containing terms with a specified prefix 5 | (not analyzed). The prefix query maps to Lucene PrefixQuery. 6 | 7 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-prefix-query.html) 8 | */ 9 | public struct Prefix: QueryElement { 10 | /// :nodoc: 11 | public static var typeKey = QueryElementMap.prefix 12 | 13 | public let field: String 14 | public let value: String 15 | public let boost: Decimal? 16 | 17 | public init(field: String, value: String, boost: Decimal?) { 18 | self.field = field 19 | self.value = value 20 | self.boost = boost 21 | } 22 | 23 | private struct Inner: Codable { 24 | let value: String 25 | let boost: Decimal? 26 | } 27 | 28 | /// :nodoc: 29 | public func encode(to encoder: Encoder) throws { 30 | var container = encoder.container(keyedBy: DynamicKey.self) 31 | let inner = Prefix.Inner(value: value, boost: boost) 32 | 33 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 34 | } 35 | 36 | /// :nodoc: 37 | public init(from decoder: Decoder) throws { 38 | let container = try decoder.container(keyedBy: DynamicKey.self) 39 | let key = container.allKeys.first 40 | self.field = key!.stringValue 41 | 42 | let innerDecoder = try container.superDecoder(forKey: key!) 43 | let inner = try Prefix.Inner(from: innerDecoder) 44 | self.value = inner.value 45 | self.boost = inner.boost 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Query.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// :nodoc: 4 | public protocol QueryElement: Codable { 5 | static var typeKey: QueryElementMap { get } 6 | } 7 | 8 | /// A `Query` starts the query portion of a search to be executed (as opposed to an `Aggregation`). 9 | public struct Query: Codable { 10 | public let query: QueryElement 11 | 12 | enum CodingKeys: String, CodingKey { 13 | case query 14 | } 15 | 16 | public init(_ query: QueryElement) { 17 | self.query = query 18 | } 19 | 20 | /// :nodoc: 21 | public func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: DynamicKey.self) 23 | 24 | try container.encode(AnyQueryElement(query), forKey: DynamicKey(stringValue: type(of: query).typeKey.rawValue)!) 25 | } 26 | 27 | /// :nodoc: 28 | public init(from decoder: Decoder) throws { 29 | let container = try decoder.container(keyedBy: DynamicKey.self) 30 | let key = container.allKeys.first 31 | let type = QueryElementMap(rawValue: key!.stringValue)! 32 | let innerDecoder = try container.superDecoder(forKey: key!) 33 | self.query = try type.metatype.init(from: innerDecoder) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Regexp.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The regexp query allows you to use regular expression term queries. See 5 | Regular expression syntax for details of the supported regular expression 6 | language. The "term queries" in that first sentence means that Elasticsearch 7 | will apply the regexp to the terms produced by the tokenizer for that field, 8 | and not to the original text of the field. 9 | 10 | Note: The performance of a regexp query heavily depends on the regular 11 | expression chosen. Matching everything like .* is very slow as well as using 12 | lookaround regular expressions. If possible, you should try to use a long 13 | prefix before your regular expression starts. Wildcard matchers like .*?+ will 14 | mostly lower performance. 15 | 16 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-regexp-query.html) 17 | */ 18 | public struct Regexp: QueryElement { 19 | /// :nodoc: 20 | public static var typeKey = QueryElementMap.regexp 21 | 22 | public let field: String 23 | public let value: String 24 | public let boost: Decimal? 25 | 26 | public init(field: String, value: String, boost: Decimal?) { 27 | self.field = field 28 | self.value = value 29 | self.boost = boost 30 | } 31 | 32 | private struct Inner: Codable { 33 | let value: String 34 | let boost: Decimal? 35 | } 36 | 37 | /// :nodoc: 38 | public func encode(to encoder: Encoder) throws { 39 | var container = encoder.container(keyedBy: DynamicKey.self) 40 | let inner = Regexp.Inner(value: value, boost: boost) 41 | 42 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 43 | } 44 | 45 | /// :nodoc: 46 | public init(from decoder: Decoder) throws { 47 | let container = try decoder.container(keyedBy: DynamicKey.self) 48 | let key = container.allKeys.first 49 | self.field = key!.stringValue 50 | 51 | let innerDecoder = try container.superDecoder(forKey: key!) 52 | let inner = try Regexp.Inner(from: innerDecoder) 53 | self.value = inner.value 54 | self.boost = inner.boost 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/AnyScoreFunction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyScoreFunction.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | /// :nodoc: 10 | public enum ScoreFunctionMap : String, Codable { 11 | 12 | case scriptScore = "script_score" 13 | case weight 14 | case randomScore = "random_score" 15 | case fieldValueFactor = "field_value_factor" 16 | case gauss 17 | case linear 18 | case exp 19 | 20 | var metatype: ScoreFunctionElement.Type { 21 | switch self { 22 | case .scriptScore: 23 | return ScriptScore.self 24 | case .weight: 25 | return WeightScore.self 26 | case .randomScore: 27 | return RandomScore.self 28 | case .fieldValueFactor: 29 | return FieldValueFactor.self 30 | case .gauss: 31 | return Gauss.self 32 | case .linear: 33 | return Linear.self 34 | case .exp: 35 | return Exp.self 36 | } 37 | } 38 | } 39 | 40 | internal struct AnyScoreFunctionElement : Codable { 41 | public var base: ScoreFunctionElement 42 | 43 | init(_ base: ScoreFunctionElement) { 44 | self.base = base 45 | } 46 | 47 | public init(from decoder: Decoder) throws { 48 | let container = try decoder.container(keyedBy: DynamicKey.self) 49 | let key = container.allKeys.first 50 | let type = ScoreFunctionMap(rawValue: key!.stringValue)! 51 | let innerDecoder = try container.superDecoder(forKey: key!) 52 | self.base = try type.metatype.init(from: innerDecoder) 53 | } 54 | 55 | public func encode(to encoder: Encoder) throws { 56 | try base.encode(to: encoder) 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/Exp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Exp.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Exp: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.exp 12 | 13 | // TODO: implement the rest of this 14 | public init() { 15 | 16 | } 17 | 18 | /// :nodoc: 19 | public func encode(to encoder: Encoder) throws {} 20 | 21 | /// :nodoc: 22 | public init(from decoder: Decoder) throws { 23 | //TODO: get from decoder 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/FieldValueFactor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FieldValueFactor.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct FieldValueFactor: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.fieldValueFactor 12 | 13 | public let field: String 14 | public let factor: Decimal? 15 | public let modifier: String? 16 | public let missing: Decimal? 17 | 18 | public init(field: String, factor: Decimal?, modifier: String?, missing: Decimal?) { 19 | self.field = field 20 | self.factor = factor 21 | self.modifier = modifier 22 | self.missing = missing 23 | } 24 | 25 | enum CodingKeys: String, CodingKey { 26 | case field 27 | case factor 28 | case modifier 29 | case missing 30 | } 31 | 32 | /// :nodoc: 33 | public func encode(to encoder: Encoder) throws { 34 | var container = encoder.container(keyedBy: CodingKeys.self) 35 | try container.encode(field, forKey: .field) 36 | try container.encodeIfPresent(factor, forKey: .factor) 37 | try container.encodeIfPresent(modifier, forKey: .modifier) 38 | try container.encodeIfPresent(missing, forKey: .missing) 39 | } 40 | 41 | /// :nodoc: 42 | public init(from decoder: Decoder) throws { 43 | let container = try decoder.container(keyedBy: CodingKeys.self) 44 | self.field = try container.decode(String.self, forKey: .field) 45 | self.factor = try container.decodeIfPresent(Decimal.self, forKey: .factor) 46 | self.modifier = try container.decodeIfPresent(String.self, forKey: .modifier) 47 | self.missing = try container.decodeIfPresent(Decimal.self, forKey: .missing) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/Linear.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Linear.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Linear: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.linear 12 | 13 | // TODO: implement the rest of this 14 | public init() { 15 | 16 | } 17 | 18 | /// :nodoc: 19 | public func encode(to encoder: Encoder) throws {} 20 | 21 | /// :nodoc: 22 | public init(from decoder: Decoder) throws { 23 | //TODO: get from decoder 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/RandomScore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Random.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct RandomScore: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.randomScore 12 | 13 | public init() { 14 | } 15 | 16 | /// :nodoc: 17 | public func encode(to encoder: Encoder) throws {} 18 | 19 | /// :nodoc: 20 | public init(from decoder: Decoder) throws {} 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/ScoreFunction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScoreFunction.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | /// :nodoc: 11 | public protocol ScoreFunctionElement: Codable { 12 | static var typeKey: ScoreFunctionMap { get } 13 | } 14 | 15 | public struct ScoreFunction: Codable { 16 | public let function: ScoreFunctionElement 17 | 18 | enum CodingKeys: String, CodingKey { 19 | case function 20 | } 21 | 22 | public init(_ function: ScoreFunctionElement) { 23 | self.function = function 24 | } 25 | 26 | /// :nodoc: 27 | public func encode(to encoder: Encoder) throws { 28 | var container = encoder.container(keyedBy: DynamicKey.self) 29 | 30 | try container.encode(AnyScoreFunctionElement(function), forKey: DynamicKey(stringValue: type(of: function).typeKey.rawValue)!) 31 | } 32 | 33 | /// :nodoc: 34 | public init(from decoder: Decoder) throws { 35 | let container = try decoder.container(keyedBy: DynamicKey.self) 36 | let key = container.allKeys.first 37 | let type = ScoreFunctionMap(rawValue: key!.stringValue)! 38 | let innerDecoder = try container.superDecoder(forKey: key!) 39 | self.function = try type.metatype.init(from: innerDecoder) 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/ScriptScore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScoreFunction.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct ScriptScore: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.scriptScore 12 | 13 | public let script: Script 14 | 15 | public init(script: Script) { 16 | self.script = script 17 | } 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case script 21 | } 22 | 23 | /// :nodoc: 24 | public func encode(to encoder: Encoder) throws { 25 | var container = encoder.container(keyedBy: CodingKeys.self) 26 | try container.encode(script, forKey: .script) 27 | } 28 | 29 | /// :nodoc: 30 | public init(from decoder: Decoder) throws { 31 | let container = try decoder.container(keyedBy: CodingKeys.self) 32 | self.script = try container.decode(Script.self, forKey: .script) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Score Functions/WeightScore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Weight.swift 3 | // Async 4 | // 5 | // Created by Kelly Bennett on 1/4/19. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct WeightScore: ScoreFunctionElement { 11 | public static var typeKey = ScoreFunctionMap.weight 12 | 13 | public let weight: Decimal 14 | 15 | public init(weight: Decimal) { 16 | self.weight = weight 17 | } 18 | 19 | /// :nodoc: 20 | public func encode(to encoder: Encoder) throws {} 21 | 22 | /// :nodoc: 23 | public init(from decoder: Decoder) throws { 24 | //TODO: get from decoder 25 | self.weight = 1 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/ScriptQuery.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A query allowing to define scripts as queries. They are typically used in a filter context. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-script-query.html) 7 | */ 8 | public struct ScriptQuery: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.script 11 | 12 | public let script: Script 13 | 14 | enum CodingKeys: String, CodingKey { 15 | case script 16 | } 17 | 18 | public init(script: Script) { 19 | self.script = script 20 | } 21 | 22 | /// :nodoc: 23 | public func encode(to encoder: Encoder) throws { 24 | var container = encoder.container(keyedBy: CodingKeys.self) 25 | try container.encode(script, forKey: .script) 26 | } 27 | 28 | /// :nodoc: 29 | public init(from decoder: Decoder) throws { 30 | let container = try decoder.container(keyedBy: CodingKeys.self) 31 | self.script = try container.decode(Script.self, forKey: .script) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/AnySpanQuery.swift: -------------------------------------------------------------------------------- 1 | 2 | public typealias SpanQueryElement = SpanQuery & QueryElement 3 | 4 | internal struct AnySpanQuery : Codable { 5 | public var base: QueryElement 6 | 7 | init(_ base: SpanQueryElement) { 8 | self.base = base 9 | } 10 | 11 | /// :nodoc: 12 | public init(from decoder: Decoder) throws { 13 | let container = try decoder.container(keyedBy: DynamicKey.self) 14 | let key = container.allKeys.first 15 | let type = QueryElementMap(rawValue: key!.stringValue)! 16 | let innerDecoder = try container.superDecoder(forKey: key!) 17 | self.base = try type.metatype.init(from: innerDecoder) 18 | } 19 | 20 | /// :nodoc: 21 | public func encode(to encoder: Encoder) throws { 22 | try base.encode(to: encoder) 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/Span.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public protocol SpanQuery: Codable { 4 | } 5 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanContaining.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanContaining: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanContaining 6 | 7 | public let little: SpanQueryElement 8 | public let big: SpanQueryElement 9 | 10 | enum CodingKeys: String, CodingKey { 11 | case little 12 | case big 13 | } 14 | 15 | public init(little: SpanQueryElement, big: SpanQueryElement) { 16 | self.little = little 17 | self.big = big 18 | } 19 | 20 | /// :nodoc: 21 | public func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: CodingKeys.self) 23 | var littleContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .little) 24 | try littleContainer.encode(AnySpanQuery(self.little), forKey: DynamicKey(stringValue: type(of: self.little).typeKey.rawValue)!) 25 | var bigContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .big) 26 | try bigContainer.encode(AnySpanQuery(self.big), forKey: DynamicKey(stringValue: type(of: self.big).typeKey.rawValue)!) 27 | } 28 | 29 | /// :nodoc: 30 | public init(from decoder: Decoder) throws { 31 | let container = try decoder.container(keyedBy: CodingKeys.self) 32 | self.little = try container.decode(AnySpanQuery.self, forKey: .little).base as! SpanQueryElement 33 | self.big = try container.decode(AnySpanQuery.self, forKey: .big).base as! SpanQueryElement 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanFirst.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanFirst: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanFirst 6 | 7 | public let match: SpanQueryElement 8 | public let end: Int 9 | 10 | enum CodingKeys: String, CodingKey { 11 | case match 12 | case end 13 | } 14 | 15 | public init(match: SpanQueryElement, end: Int) { 16 | self.match = match 17 | self.end = end 18 | } 19 | 20 | /// :nodoc: 21 | public func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: CodingKeys.self) 23 | var matchContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .match) 24 | try matchContainer.encode(AnySpanQuery(self.match), forKey: DynamicKey(stringValue: type(of: self.match).typeKey.rawValue)!) 25 | try container.encode(end, forKey: .end) 26 | } 27 | 28 | /// :nodoc: 29 | public init(from decoder: Decoder) throws { 30 | let container = try decoder.container(keyedBy: CodingKeys.self) 31 | self.match = try container.decode(AnySpanQuery.self, forKey: .match).base as! SpanQueryElement 32 | self.end = try container.decode(Int.self, forKey: .end) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanNear.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanNear: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanNear 6 | 7 | public let clauses: [SpanQueryElement] 8 | public let slop: Int? 9 | public let inOrder: Bool? 10 | 11 | enum CodingKeys: String, CodingKey { 12 | case clauses 13 | case slop 14 | case inOrder = "in_order" 15 | } 16 | 17 | public init(_ clauses: [SpanQueryElement], slop: Int? = nil, inOrder: Bool? = nil) { 18 | self.clauses = clauses 19 | self.slop = slop 20 | self.inOrder = inOrder 21 | } 22 | 23 | /// :nodoc: 24 | public func encode(to encoder: Encoder) throws { 25 | var container = encoder.container(keyedBy: CodingKeys.self) 26 | var clausesContainer = container.nestedUnkeyedContainer(forKey: .clauses) 27 | for clause in self.clauses { 28 | var clauseContainer = clausesContainer.nestedContainer(keyedBy: DynamicKey.self) 29 | try clauseContainer.encode(AnySpanQuery(clause), forKey: DynamicKey(stringValue: type(of: clause).typeKey.rawValue)!) 30 | } 31 | try container.encodeIfPresent(slop, forKey: .slop) 32 | try container.encodeIfPresent(inOrder, forKey: .inOrder) 33 | } 34 | 35 | /// :nodoc: 36 | public init(from decoder: Decoder) throws { 37 | let container = try decoder.container(keyedBy: CodingKeys.self) 38 | self.clauses = try container.decode([AnySpanQuery].self, forKey: .clauses).map { $0.base } as! [SpanQueryElement] 39 | self.slop = try container.decodeIfPresent(Int.self, forKey: .slop) 40 | self.inOrder = try container.decodeIfPresent(Bool.self, forKey: .inOrder) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanNot.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanNot: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanNot 6 | 7 | public let include: SpanQueryElement 8 | public let exclude: SpanQueryElement 9 | 10 | public let pre: Int? 11 | public let post: Int? 12 | public let dist: Int? 13 | 14 | enum CodingKeys: String, CodingKey { 15 | case include 16 | case exclude 17 | case pre 18 | case post 19 | case dist 20 | } 21 | 22 | public init(include: SpanQueryElement, exclude: SpanQueryElement, pre: Int? = nil, post: Int? = nil, dist: Int? = nil) { 23 | self.include = include 24 | self.exclude = exclude 25 | self.pre = pre 26 | self.post = post 27 | self.dist = dist 28 | } 29 | 30 | /// :nodoc: 31 | public func encode(to encoder: Encoder) throws { 32 | var container = encoder.container(keyedBy: CodingKeys.self) 33 | var includeContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .include) 34 | try includeContainer.encode(AnySpanQuery(self.include), forKey: DynamicKey(stringValue: type(of: self.include).typeKey.rawValue)!) 35 | var excludeContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .exclude) 36 | try excludeContainer.encode(AnySpanQuery(self.exclude), forKey: DynamicKey(stringValue: type(of: self.exclude).typeKey.rawValue)!) 37 | 38 | try container.encodeIfPresent(pre, forKey: .pre) 39 | try container.encodeIfPresent(post, forKey: .post) 40 | try container.encodeIfPresent(dist, forKey: .dist) 41 | } 42 | 43 | /// :nodoc: 44 | public init(from decoder: Decoder) throws { 45 | let container = try decoder.container(keyedBy: CodingKeys.self) 46 | self.include = try container.decode(AnySpanQuery.self, forKey: .include).base as! SpanQueryElement 47 | self.exclude = try container.decode(AnySpanQuery.self, forKey: .exclude).base as! SpanQueryElement 48 | self.pre = try container.decodeIfPresent(Int.self, forKey: .pre) 49 | self.post = try container.decodeIfPresent(Int.self, forKey: .post) 50 | self.dist = try container.decodeIfPresent(Int.self, forKey: .dist) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanOr.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanOr: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanOr 6 | 7 | public let clauses: [SpanQueryElement] 8 | 9 | enum CodingKeys: String, CodingKey { 10 | case clauses 11 | } 12 | 13 | public init(_ clauses: [SpanQueryElement]) { 14 | self.clauses = clauses 15 | } 16 | 17 | /// :nodoc: 18 | public func encode(to encoder: Encoder) throws { 19 | var container = encoder.container(keyedBy: CodingKeys.self) 20 | var clausesContainer = container.nestedUnkeyedContainer(forKey: .clauses) 21 | for clause in self.clauses { 22 | var clauseContainer = clausesContainer.nestedContainer(keyedBy: DynamicKey.self) 23 | try clauseContainer.encode(AnySpanQuery(clause), forKey: DynamicKey(stringValue: type(of: clause).typeKey.rawValue)!) 24 | } 25 | } 26 | 27 | /// :nodoc: 28 | public init(from decoder: Decoder) throws { 29 | let container = try decoder.container(keyedBy: CodingKeys.self) 30 | self.clauses = try container.decode([AnySpanQuery].self, forKey: .clauses).map { $0.base } as! [SpanQueryElement] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanTerm.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanTerm: SpanQuery, QueryElement { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanTerm 6 | 7 | public let field: String 8 | public let term: String 9 | public let boost: Decimal? 10 | 11 | public init(field: String, term: String, boost: Decimal? = nil) { 12 | self.field = field 13 | self.term = term 14 | self.boost = boost 15 | } 16 | 17 | private struct Inner: Codable { 18 | let term: String 19 | let boost: Decimal? 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case term 23 | case boost 24 | } 25 | } 26 | 27 | /// :nodoc: 28 | public func encode(to encoder: Encoder) throws { 29 | var container = encoder.container(keyedBy: DynamicKey.self) 30 | let inner = SpanTerm.Inner(term: term, boost: boost) 31 | 32 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 33 | } 34 | 35 | /// :nodoc: 36 | public init(from decoder: Decoder) throws { 37 | let container = try decoder.container(keyedBy: DynamicKey.self) 38 | let key = container.allKeys.first 39 | self.field = key!.stringValue 40 | 41 | let innerDecoder = try container.superDecoder(forKey: key!) 42 | let inner = try SpanTerm.Inner(from: innerDecoder) 43 | self.term = inner.term 44 | self.boost = inner.boost 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/SpanQueries/SpanWithin.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SpanWithin: QueryElement, SpanQuery { 4 | /// :nodoc: 5 | public static var typeKey = QueryElementMap.spanWithin 6 | 7 | public let little: SpanQueryElement 8 | public let big: SpanQueryElement 9 | 10 | enum CodingKeys: String, CodingKey { 11 | case little 12 | case big 13 | } 14 | 15 | public init(little: SpanQueryElement, big: SpanQueryElement) { 16 | self.little = little 17 | self.big = big 18 | } 19 | 20 | /// :nodoc: 21 | public func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: CodingKeys.self) 23 | var littleContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .little) 24 | try littleContainer.encode(AnySpanQuery(self.little), forKey: DynamicKey(stringValue: type(of: self.little).typeKey.rawValue)!) 25 | var bigContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .big) 26 | try bigContainer.encode(AnySpanQuery(self.big), forKey: DynamicKey(stringValue: type(of: self.big).typeKey.rawValue)!) 27 | } 28 | 29 | /// :nodoc: 30 | public init(from decoder: Decoder) throws { 31 | let container = try decoder.container(keyedBy: CodingKeys.self) 32 | self.little = try container.decode(AnySpanQuery.self, forKey: .little).base as! SpanQueryElement 33 | self.big = try container.decode(AnySpanQuery.self, forKey: .big).base as! SpanQueryElement 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Suggest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Suggest: Encodable { 4 | public let name: String 5 | public let prefix: String 6 | public let field: String 7 | 8 | public init(name: String, prefix: String, field: String) { 9 | self.name = name 10 | self.prefix = prefix 11 | self.field = field 12 | } 13 | 14 | public func encode(to encoder: Encoder) throws { 15 | var container = encoder.container(keyedBy: CodingKeys.self) 16 | var completion = container.nestedContainer(keyedBy: CompletionKeys.self, forKey: .completion) 17 | 18 | try container.encode(prefix, forKey: .prefix) 19 | try completion.encode(field, forKey: .field) 20 | } 21 | 22 | enum CodingKeys: String, CodingKey { 23 | case prefix 24 | case completion 25 | } 26 | 27 | enum CompletionKeys: String, CodingKey { 28 | case field 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Term.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | The `Term` query finds documents that contain the exact term specified in the inverted index. 5 | 6 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-term-query.html) 7 | */ 8 | public struct Term: QueryElement { 9 | /// :nodoc: 10 | public static var typeKey = QueryElementMap.term 11 | 12 | public let field: String 13 | public let value: String 14 | public let boost: Decimal? 15 | 16 | public init(field: String, value: String, boost: Decimal? = nil) { 17 | self.field = field 18 | self.value = value 19 | self.boost = boost 20 | } 21 | 22 | private struct Inner: Codable { 23 | let value: String 24 | let boost: Decimal? 25 | } 26 | 27 | /// :nodoc: 28 | public func encode(to encoder: Encoder) throws { 29 | var container = encoder.container(keyedBy: DynamicKey.self) 30 | let inner = Term.Inner(value: value, boost: boost) 31 | 32 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 33 | } 34 | 35 | /// :nodoc: 36 | public init(from decoder: Decoder) throws { 37 | let container = try decoder.container(keyedBy: DynamicKey.self) 38 | let key = container.allKeys.first 39 | self.field = key!.stringValue 40 | 41 | let innerDecoder = try container.superDecoder(forKey: key!) 42 | let inner = try Term.Inner(from: innerDecoder) 43 | self.value = inner.value 44 | self.boost = inner.boost 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Query/Wildcard.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | Matches documents that have fields matching a wildcard expression (not 5 | analyzed). Supported wildcards are *, which matches any character sequence 6 | (including the empty one), and ?, which matches any single character. Note 7 | that this query can be slow, as it needs to iterate over many terms. In order 8 | to prevent extremely slow wildcard queries, a wildcard term should not start 9 | with one of the wildcards * or ?. 10 | 11 | [More information](https://www.elastic.co/guide/en/elasticsearch/reference/6.3/query-dsl-wildcard-query.html) 12 | */ 13 | public struct Wildcard: QueryElement { 14 | /// :nodoc: 15 | public static var typeKey = QueryElementMap.wildcard 16 | 17 | public let field: String 18 | public let value: String 19 | public let boost: Decimal? 20 | 21 | public init(field: String, value: String, boost: Decimal?) { 22 | self.field = field 23 | self.value = value 24 | self.boost = boost 25 | } 26 | 27 | private struct Inner: Codable { 28 | let value: String 29 | let boost: Decimal? 30 | } 31 | 32 | /// :nodoc: 33 | public func encode(to encoder: Encoder) throws { 34 | var container = encoder.container(keyedBy: DynamicKey.self) 35 | let inner = Wildcard.Inner(value: value, boost: boost) 36 | 37 | try container.encode(inner, forKey: DynamicKey(stringValue: field)!) 38 | } 39 | 40 | /// :nodoc: 41 | public init(from decoder: Decoder) throws { 42 | let container = try decoder.container(keyedBy: DynamicKey.self) 43 | let key = container.allKeys.first 44 | self.field = key!.stringValue 45 | 46 | let innerDecoder = try container.superDecoder(forKey: key!) 47 | let inner = try Wildcard.Inner(from: innerDecoder) 48 | self.value = inner.value 49 | self.boost = inner.boost 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/SearchContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | This is the topmost container for specifying a query. 5 | */ 6 | public struct SearchContainer: Encodable { 7 | public let query: Query? 8 | public let sort: [Sort]? 9 | public let aggs: [Aggregation]? 10 | public let from: Int 11 | public let size: Int 12 | public let terminateAfter: Int? 13 | 14 | enum CodingKeys: String, CodingKey { 15 | case query 16 | case sort 17 | case aggs 18 | case from 19 | case size 20 | case terminateAfter = "terminate_after" 21 | } 22 | 23 | public init(aggs: [Aggregation]) { 24 | self.init(query: nil, aggs: aggs) 25 | } 26 | 27 | public init( 28 | _ query: Query, 29 | sort: [Sort]? = nil, 30 | aggs: [Aggregation]? = nil, 31 | from: Int = 0, 32 | size: Int = 10, 33 | terminateAfter: Int? = nil 34 | ) { 35 | self.init(query: query, sort: sort, aggs: aggs, from: from, size: size) 36 | } 37 | 38 | private init( 39 | query: Query? = nil, 40 | sort: [Sort]? = nil, 41 | aggs: [Aggregation]? = nil, 42 | from: Int = 0, 43 | size: Int = 10, 44 | terminateAfter: Int? = nil 45 | ) { 46 | self.query = query 47 | self.sort = sort 48 | self.aggs = aggs 49 | self.from = from 50 | self.size = query == nil ? 0 : size 51 | self.terminateAfter = terminateAfter 52 | } 53 | 54 | public func encode(to encoder: Encoder) throws { 55 | var container = encoder.container(keyedBy: CodingKeys.self) 56 | 57 | try container.encode(from, forKey: .from) 58 | try container.encode(size, forKey: .size) 59 | 60 | try container.encodeIfPresent(query, forKey: .query) 61 | try container.encodeIfPresent(sort, forKey: .sort) 62 | 63 | if aggs != nil && aggs!.count > 0 { 64 | var aggContainer = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .aggs) 65 | for agg in aggs! { 66 | try aggContainer.encode(AnyAggregation(agg), forKey: DynamicKey(stringValue: agg.name)!) 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Sort/Sort.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct Sort: Codable { 4 | let key: String 5 | let order: SortOrder 6 | 7 | public init(_ key: String, _ order: SortOrder) { 8 | self.key = key 9 | self.order = order 10 | } 11 | 12 | public init(from decoder: Decoder) throws { 13 | let container = try decoder.container(keyedBy: DynamicKey.self) 14 | let key = container.allKeys[0] 15 | self.key = key.stringValue 16 | 17 | let valuesContainer = try container.nestedContainer(keyedBy: NestedKeys.self, forKey: key) 18 | self.order = try valuesContainer.decode(SortOrder.self, forKey: .order) 19 | } 20 | 21 | public func encode(to encoder: Encoder) throws { 22 | var container = encoder.container(keyedBy: DynamicKey.self) 23 | var valuesContainer = container.nestedContainer(keyedBy: NestedKeys.self, forKey: DynamicKey(stringValue: key)!) 24 | 25 | try valuesContainer.encode(order, forKey: .order) 26 | } 27 | 28 | enum NestedKeys: String, CodingKey { 29 | case order 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/Sort/SortOrder.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum SortOrder: String, Codable { 4 | case ascending = "asc" 5 | case descending = "desc" 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Search/SuggestContainer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct SuggestContainer: Encodable { 4 | public let suggests: [Suggest] 5 | 6 | public init(suggests: [Suggest]) { 7 | self.suggests = suggests 8 | } 9 | 10 | public func encode(to encoder: Encoder) throws { 11 | var container = encoder.container(keyedBy: CodingKeys.self) 12 | var suggestNode = container.nestedContainer(keyedBy: DynamicKey.self, forKey: .suggest) 13 | 14 | try suggests.forEach { suggest in 15 | try suggestNode.encode(suggest, forKey: DynamicKey(stringValue: suggest.name)!) 16 | } 17 | } 18 | 19 | enum CodingKeys: String, CodingKey { 20 | case suggest 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Utilities/DynamicKey.swift: -------------------------------------------------------------------------------- 1 | struct DynamicKey: CodingKey { 2 | var intValue: Int? { return nil } 3 | var stringValue: String 4 | 5 | init?(intValue: Int) { return nil } 6 | 7 | init?(stringValue: String) { 8 | self.stringValue = stringValue 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Utilities/ElasticsearchError.swift: -------------------------------------------------------------------------------- 1 | import Debugging 2 | import COperatingSystem 3 | 4 | /// Errors that can be thrown while working with Elasticsearch. 5 | public struct ElasticsearchError: Debuggable { 6 | public static let readableName = "Elasticsearch Error" 7 | public let identifier: String 8 | public var reason: String 9 | public var sourceLocation: SourceLocation? 10 | public var stackTrace: [String] 11 | public var possibleCauses: [String] 12 | public var suggestedFixes: [String] 13 | public var statusCode: UInt? 14 | 15 | /// Create a new Elasticsearch error. 16 | public init( 17 | identifier: String, 18 | reason: String, 19 | possibleCauses: [String] = [], 20 | suggestedFixes: [String] = [], 21 | source: SourceLocation, 22 | statusCode: UInt? = nil 23 | ) { 24 | self.identifier = identifier 25 | self.reason = reason 26 | self.sourceLocation = source 27 | self.stackTrace = ElasticsearchError.makeStackTrace() 28 | self.possibleCauses = possibleCauses 29 | self.suggestedFixes = suggestedFixes 30 | self.statusCode = statusCode 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Elasticsearch/Utilities/Exports.swift: -------------------------------------------------------------------------------- 1 | @_exported import Async 2 | @_exported import DatabaseKit 3 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | ## TODO 3 | 4 | * Implement more aggregation types, especially bucketed 5 | * Ability to get back raw results 6 | * Implement the KeyedCacheSupporting protocol 7 | * Implement the DatabaseQueryable protocol 8 | * Create a chainable query builder 9 | * Implement remaining query DSL constructors 10 | These are the remaining query DSL constructors that are left to be 11 | implemented. They are not all of equal value. But pick off those that seem 12 | useful/easy first. 13 | 14 | * [Query string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html) 15 | * [Simple query string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) 16 | * [Terms set](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-set-query.html) 17 | * [Span multi-term query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-multi-term-query.html) 18 | * [Span field masking query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-span-field-masking-query.html) 19 | * [Boosting query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-boosting-query.html) 20 | * [Constant score query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-constant-score-query.html) 21 | * [Has child query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-child-query.html) 22 | * [Has parent query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-has-parent-query.html) 23 | * [Parent ID query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-parent-id-query.html) 24 | * [Geo shape query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-shape-query.html) 25 | * [Geo bounding box](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-bounding-box-query.html) 26 | * [Geo distance](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-query.html) 27 | * [More like this query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html) 28 | * [Percolate query](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-percolate-query.html) 29 | 30 | * Documentation 31 | * More unit tests 32 | * Need tests for encoding/decoding round trips of the Map types 33 | 34 | -------------------------------------------------------------------------------- /Tests/ElasticsearchTests/Analysis/NormalizerTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Elasticsearch 3 | 4 | final class NormalizerTests: XCTestCase { 5 | var encoder: JSONEncoder! 6 | var decoder: JSONDecoder! 7 | 8 | override func setUp() { 9 | encoder = JSONEncoder() 10 | decoder = JSONDecoder() 11 | } 12 | 13 | func testCustomNormalizer_encodesCorrectly() throws { 14 | let es = try ElasticsearchClient.makeTest() 15 | defer { es.close() } 16 | 17 | let json = """ 18 | {"settings":{"analysis":{"normalizer":{"test_normalizer":{"type":"custom","filter":["foo","bar"]}}}},"mappings":{"_doc":{"properties":{"foo":{"type":"keyword","normalizer":"test_normalizer"}},"enabled":true,"dynamic":false,"_meta":{"private":{"serialVersion":1,"propertiesHash":""}}}}} 19 | """ 20 | 21 | let map = MapKeyword(normalizer: CustomNormalizer(name: "test_normalizer", filter: ["foo", "bar"])) 22 | let index = es.configureIndex(name: "test").property(key: "foo", type: map) 23 | 24 | let encoded = try encoder.encodeToString(index) 25 | XCTAssertEqual(json, encoded) 26 | } 27 | 28 | func testLinuxTestSuiteIncludesAllTests() { 29 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 30 | let thisClass = type(of: self) 31 | let linuxCount = thisClass.allTests.count 32 | let darwinCount = Int(thisClass.defaultTestSuite.testCaseCount) 33 | XCTAssertEqual(linuxCount, darwinCount, "\(darwinCount - linuxCount) tests are missing from allTests") 34 | #endif 35 | } 36 | 37 | static var allTests = [ 38 | ("testCustomNormalizer_encodesCorrectly", testCustomNormalizer_encodesCorrectly), 39 | 40 | ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Tests/ElasticsearchTests/TestHelpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | import Elasticsearch 4 | 5 | extension JSONEncoder { 6 | func encodeToString(_ value: T) throws -> String where T : Encodable { 7 | let data = try self.encode(value) 8 | 9 | return String(data: data, encoding: .utf8)! 10 | } 11 | } 12 | 13 | internal extension Environment { 14 | static var xcode: Environment { 15 | return .init(name: "xcode", isRelease: false, arguments: ["xcode"]) 16 | } 17 | } 18 | 19 | extension ElasticsearchClient { 20 | /// Creates a test event loop and Elasticsearch client. 21 | static func makeTest() throws -> ElasticsearchClient { 22 | let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) 23 | let config = ElasticsearchClientConfig() 24 | let client = try ElasticsearchClient.connect(config: config, on: group).wait() 25 | return client 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/ElasticsearchTests/VaporIntegrationTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import Elasticsearch 3 | import Vapor 4 | 5 | final class VaporIntegrationTests: XCTestCase { 6 | func testBootSequence() throws { 7 | var services = Services.default() 8 | 9 | var config = ElasticsearchClientConfig() 10 | config.hostname = "localhost" 11 | config.port = 9200 12 | config.enableKeyedCache = true 13 | config.keyedCacheIndexName = "vapor_keyed_cache_3" 14 | 15 | try services.register(ElasticsearchProvider(config)) 16 | 17 | let _ = try Application.asyncBoot(config: .default(), environment: .xcode, services: services).wait() 18 | } 19 | 20 | func testLinuxTestSuiteIncludesAllTests() { 21 | #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) 22 | let thisClass = type(of: self) 23 | let linuxCount = thisClass.allTests.count 24 | let darwinCount = Int(thisClass.defaultTestSuite.testCaseCount) 25 | XCTAssertEqual(linuxCount, darwinCount, "\(darwinCount - linuxCount) tests are missing from allTests") 26 | #endif 27 | } 28 | 29 | static var allTests = [ 30 | ("testBootSequence", testBootSequence), 31 | 32 | ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests) 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /Tests/ElasticsearchTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !os(macOS) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(ElasticsearchTests.allTests), 7 | testCase(ElasticsearchQueryCodingTests.allTests), 8 | testCase(ElasticsearchAggregationCodingTests.allTests), 9 | testCase(NormalizerTests.allTests), 10 | testCase(TokenizerTests.allTests), 11 | testCase(CharacterFilterTests.allTests), 12 | testCase(TokenFilterTests.allTests), 13 | testCase(AnalyzerTests.allTests), 14 | testCase(VaporIntegrationTests.allTests) 15 | ] 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import ElasticsearchTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += ElasticsearchTests.allTests() 7 | XCTMain(tests) -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 23% 23 | 24 | 25 | 23% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.elasticsearch 7 | CFBundleName 8 | Elasticsearch 9 | DocSetPlatformFamily 10 | elasticsearch 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/docsets/Elasticsearch.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/Elasticsearch.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/docsets/Elasticsearch.tgz -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ryangrimm/VaporElasticsearch/fef7dc43bfb419e51f59a8911125c5d90942e8c6/docs/img/gh.png -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | window.jazzy = {'docset': false} 2 | if (typeof window.dash != 'undefined') { 3 | document.documentElement.className += ' dash' 4 | window.jazzy.docset = true 5 | } 6 | if (navigator.userAgent.match(/xcode/i)) { 7 | document.documentElement.className += ' xcode' 8 | window.jazzy.docset = true 9 | } 10 | 11 | // On doc load, toggle the URL hash discussion if present 12 | $(document).ready(function() { 13 | if (!window.jazzy.docset) { 14 | var linkToHash = $('a[href="' + window.location.hash +'"]'); 15 | linkToHash.trigger("click"); 16 | } 17 | }); 18 | 19 | // On token click, toggle its discussion and animate token.marginLeft 20 | $(".token").click(function(event) { 21 | if (window.jazzy.docset) { 22 | return; 23 | } 24 | var link = $(this); 25 | var animationDuration = 300; 26 | var tokenOffset = "15px"; 27 | var original = link.css('marginLeft') == tokenOffset; 28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration); 29 | $content = link.parent().parent().next(); 30 | $content.slideToggle(animationDuration); 31 | 32 | // Keeps the document from jumping to the hash. 33 | var href = $(this).attr('href'); 34 | if (history.pushState) { 35 | history.pushState({}, '', href); 36 | } else { 37 | location.hash = href; 38 | } 39 | event.preventDefault(); 40 | }); 41 | 42 | // Dumb down quotes within code blocks that delimit strings instead of quotations 43 | // https://github.com/realm/jazzy/issues/714 44 | $("code q").replaceWith(function () { 45 | return ["\"", $(this).contents(), "\""]; 46 | }); 47 | --------------------------------------------------------------------------------