typesensual 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'typesensual/search/hit'
4
+ require 'typesensual/search/results'
5
+
6
+ class Typesensual
7
+ class Search
8
+ # Initialize a new search object for a collection
9
+ #
10
+ # @param collection [Typesensual::Collection] the Typesensual collection object
11
+ # @param query [String] the query string to search for
12
+ # @param query_by [String, Symbol, Array<String, Symbol>, Hash<String, Symbol>] the fields to
13
+ # search in. If a hash is provided, the keys are the fields and the values are the weights.
14
+ # If a string is provided, it is used directly as the query_by parameter. If an array is
15
+ # provided, the values are the fields.
16
+ def initialize(collection:, query:, query_by:)
17
+ @filter_by = []
18
+ @sort_by = []
19
+ @facet_by = []
20
+ @facet_query = []
21
+ @include_fields = []
22
+ @exclude_fields = []
23
+ @params = {}
24
+
25
+ @collection = collection
26
+ @query = query
27
+
28
+ if query_by.is_a?(Hash)
29
+ @query_by = query_by.keys
30
+ @query_by_weights = query_by.values
31
+ elsif query_by.is_a?(String) || query_by.is_a?(Symbol)
32
+ @query_by = [query_by]
33
+ else
34
+ @query_by = query_by
35
+ end
36
+ end
37
+
38
+ # Set the number of results to return per page
39
+ # @param count [Integer] the number of results to return per page
40
+ def per(count)
41
+ set(per_page: count)
42
+ end
43
+
44
+ # Set the page number to return
45
+ # @param number [Integer] the page number to return
46
+ def page(number)
47
+ set(page: number)
48
+ end
49
+
50
+ # Add a filter to the search
51
+ # @param filter [String, Symbol, Hash<String, Symbol>] the filter to add. If a hash is
52
+ # provided, the keys are the fields and the values are the values to filter by. If a
53
+ # string is provided, it is added directly as a filter. All filters are ANDed together.
54
+ def filter(filter)
55
+ if filter.is_a?(Hash)
56
+ @filter_by += filter.map { |key, value| "#{key}:#{value}" }
57
+ else
58
+ @filter_by << filter.to_s
59
+ end
60
+ self
61
+ end
62
+
63
+ # Add a sort to the search
64
+ # @param value [String, Symbol, Hash<String, Symbol>] the sort to add to the search. If
65
+ # a hash is provided, the keys are the fields and the values are the directions to sort.
66
+ # If a string is provided, it is added directly as a sort.
67
+ def sort(value)
68
+ if value.is_a?(Hash)
69
+ @sort_by += value.map { |key, direction| "#{key}:#{direction}" }
70
+ else
71
+ @sort_by << value.to_s
72
+ end
73
+ self
74
+ end
75
+
76
+ # Add a field to facet to the seach
77
+ # @param facets [String, Symbol, Array<String, Symbol>, Hash<String, Symbol>] the fields to
78
+ # facet by. If a hash is provided, the keys are the fields and the values are strings to
79
+ # query each facet. If an Array is provided, the values are fields to facet by. If a string
80
+ # is provided, it is added directly as a facet.
81
+ def facet(facets)
82
+ if facets.is_a?(Hash)
83
+ facets.each do |key, value|
84
+ @facet_by << key.to_s
85
+ @facet_query << "#{key}:#{value}" if value
86
+ end
87
+ elsif facets.is_a?(Array)
88
+ @facet_by += facets.map(&:to_s)
89
+ else
90
+ @facet_by << facets.to_s
91
+ end
92
+ self
93
+ end
94
+
95
+ # Add fields to include in the search result documents
96
+ # @param fields [String, Symbol, Array<String, Symbol>] the fields to include
97
+ def include_fields(*fields)
98
+ @include_fields += fields.map(&:to_s)
99
+ self
100
+ end
101
+
102
+ # Add fields to exclude from the search result documents
103
+ # @param fields [String, Symbol, Array<String, Symbol>] the fields to exclude
104
+ def exclude_fields(*fields)
105
+ @exclude_fields += fields.map(&:to_s)
106
+ self
107
+ end
108
+
109
+ # Set additional parameters to pass to the search
110
+ # @param values [Hash] the parameters to set
111
+ def set(values)
112
+ @params.merge!(values)
113
+ self
114
+ end
115
+
116
+ # Generate the query document
117
+ def query
118
+ {
119
+ collection: @collection.name,
120
+ filter_by: @filter_by.join(' && '),
121
+ q: @query,
122
+ query_by: @query_by&.join(','),
123
+ query_by_weights: @query_by_weights&.join(','),
124
+ sort_by: @sort_by&.join(','),
125
+ facet_by: @facet_by&.join(','),
126
+ facet_query: @facet_query&.join(','),
127
+ include_fields: @include_fields&.join(','),
128
+ exclude_fields: @exclude_fields&.join(',')
129
+ }.merge(@params).reject { |_, v| v.blank? }
130
+ end
131
+
132
+ # Load the results from the search query
133
+ def load
134
+ Results.new(@collection.typesense_collection.documents.search(query))
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Typesensual
4
+ module StateHelpers
5
+ extend ActiveSupport::Concern
6
+
7
+ delegate :config, :env, :client, to: :class
8
+
9
+ class_methods do
10
+ delegate :config, to: :Typesensual
11
+ delegate :env, :client, to: :config, allow_nil: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Typesensual
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require 'active_support/concern'
6
+ require 'active_support/core_ext/string/inflections'
7
+ require 'active_support/core_ext/class/subclasses'
8
+ require 'active_support/core_ext/module/delegation'
9
+ require 'active_support/core_ext/hash/keys'
10
+
11
+ require 'typesense'
12
+
13
+ require 'typesensual/version'
14
+ require 'typesensual/config'
15
+ require 'typesensual/index'
16
+ require 'typesensual/collection'
17
+ require 'typesensual/search'
18
+ require 'typesensual/railtie' if defined?(Rails)
19
+
20
+ class Typesensual
21
+ class << self
22
+ attr_accessor :config
23
+
24
+ def client
25
+ config&.client
26
+ end
27
+
28
+ def configure(&block)
29
+ self.config = Typesensual::Config.new(&block)
30
+ end
31
+
32
+ # Get the collections that match the alias name
33
+ #
34
+ # @return [Array<Collection>] the collections that match the alias name
35
+ def collections
36
+ Typesensual.client.collections.retrieve.map do |collection|
37
+ Collection.new(collection)
38
+ end
39
+ end
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: typesensual
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Emma Lejeck
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-07-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 6.1.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 6.1.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: paint
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: typesense
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.13.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.13.0
55
+ description:
56
+ email:
57
+ - nuck@kitsu.io
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rspec"
63
+ - ".rubocop.yml"
64
+ - ".ruby-version"
65
+ - ".yardopts"
66
+ - CHANGELOG.md
67
+ - Gemfile
68
+ - Gemfile.lock
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - lib/tasks/typesensual.rake
73
+ - lib/typesensual.rb
74
+ - lib/typesensual/callbacks.rb
75
+ - lib/typesensual/collection.rb
76
+ - lib/typesensual/config.rb
77
+ - lib/typesensual/field.rb
78
+ - lib/typesensual/index.rb
79
+ - lib/typesensual/railtie.rb
80
+ - lib/typesensual/rake_helper.rb
81
+ - lib/typesensual/schema.rb
82
+ - lib/typesensual/search.rb
83
+ - lib/typesensual/search/hit.rb
84
+ - lib/typesensual/search/results.rb
85
+ - lib/typesensual/state_helpers.rb
86
+ - lib/typesensual/version.rb
87
+ homepage: https://github.com/hummingbird-me/typesensual
88
+ licenses:
89
+ - MIT
90
+ metadata:
91
+ homepage_uri: https://github.com/hummingbird-me/typesensual
92
+ source_code_uri: https://github.com/hummingbird-me/typesensual
93
+ changelog_uri: https://github.com/hummingbird-me/typesensual/blob/main/CHANGELOG.md
94
+ rubygems_mfa_required: 'true'
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.7.0
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubygems_version: 3.3.26
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: A simple, sensual wrapper around Typesense for Ruby
114
+ test_files: []