typesensual 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +293 -0
- data/.ruby-version +1 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +111 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +6 -0
- data/lib/tasks/typesensual.rake +24 -0
- data/lib/typesensual/callbacks.rb +22 -0
- data/lib/typesensual/collection.rb +202 -0
- data/lib/typesensual/config.rb +26 -0
- data/lib/typesensual/field.rb +52 -0
- data/lib/typesensual/index.rb +161 -0
- data/lib/typesensual/railtie.rb +9 -0
- data/lib/typesensual/rake_helper.rb +103 -0
- data/lib/typesensual/schema.rb +49 -0
- data/lib/typesensual/search/hit.rb +43 -0
- data/lib/typesensual/search/results.rb +51 -0
- data/lib/typesensual/search.rb +137 -0
- data/lib/typesensual/state_helpers.rb +14 -0
- data/lib/typesensual/version.rb +5 -0
- data/lib/typesensual.rb +41 -0
- metadata +114 -0
@@ -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
|
data/lib/typesensual.rb
ADDED
@@ -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: []
|