solrbee 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba9c7b336f903632e73bba3dc8b7689a11581dbac82db1a5e766edc427f12a1d
4
- data.tar.gz: 508e84b7cafb3e65a71eb95d6e8afe1a76df69cced60ad4d7f770685cd63caa4
3
+ metadata.gz: 77e7ebc45077bb8016d699124b9d4de397adba4d6166e0b3f64bb07693c51a3f
4
+ data.tar.gz: 846ea941962ac61ac49195bc0a05ef4356fbc0937a96055af43320c833b41b5d
5
5
  SHA512:
6
- metadata.gz: 47e306541ae1e6551b3a45212045970533d4d6fee01f6ac70c291d08bc618f9a964d513c6517d534e66568c60605213a0a4aa33c3bd2dd20660f27f761dcb40f
7
- data.tar.gz: 6cf7560f0015d0d564e0e6c897f34c4b90a1d76e962f729cdc4a565775589c456f1c15d2d17066f2e0b5f5c42b0b24c32ff9814040e353694e36680291751cea
6
+ metadata.gz: 278f91339f713389ab9858471f35f8a72d07ae1e00083e931cade7af50aee540ba8abf1bd42a79f1a1ffa11ab3b081f8a3231035642ff61091abc7f8f3306da5
7
+ data.tar.gz: a143efa02fed4ee7e10c063bf4c4db6df6df5f9bbf40ba820c004c4961e206545d980ed615f566b99c996f30db184a49fce7a005d990ebbca4b9028cddadaebf
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem "rom-http", git: "https://github.com/rom-rb/rom-http.git"
@@ -0,0 +1,45 @@
1
+ v1:
2
+ ping:
3
+ path: /admin/ping
4
+ response_key: status
5
+
6
+ schema:
7
+ path: /schema
8
+ response_key: schema
9
+
10
+ schema_name:
11
+ path: /schema/name
12
+ response_key: name
13
+
14
+ schema_version:
15
+ path: /schema/version
16
+ response_key: version
17
+
18
+ fields:
19
+ path: /schema/fields
20
+ response_key: fields
21
+
22
+ field:
23
+ path: /schema/fields/%{name}
24
+ response_key: field
25
+
26
+ unique_key:
27
+ path: /schema/uniquekey
28
+ response_key: uniqueKey
29
+
30
+ field_types:
31
+ path: /schema/fieldtypes
32
+ response_key: fieldTypes
33
+
34
+ field_type:
35
+ path: /schema/fieldtypes/%{name}
36
+ response_key: fieldType
37
+
38
+ update:
39
+ path: /update
40
+
41
+ update_json:
42
+ path: /update/json
43
+
44
+ update_json_docs:
45
+ path: /update/json/docs
@@ -0,0 +1,22 @@
1
+ require 'rom-http'
2
+
3
+ require_relative 'solr/request'
4
+ require_relative 'solr/response'
5
+
6
+ require_relative 'solr/dataset'
7
+ require_relative 'solr/datasets/select_dataset'
8
+
9
+ require_relative 'solr/gateway'
10
+
11
+ require_relative 'solr/schemaless'
12
+
13
+ require_relative 'solr/relation'
14
+ require_relative 'solr/relations/schema_relation'
15
+ require_relative 'solr/relations/select_relation'
16
+
17
+ module ROM
18
+ module Solr
19
+ end
20
+
21
+ register_adapter(:solr, ROM::Solr)
22
+ end
@@ -0,0 +1,93 @@
1
+ module ROM
2
+ module Solr
3
+ class Dataset < ROM::HTTP::Dataset
4
+
5
+ # Key or array of keys to pass to response.dig(*keys)
6
+ # for enumeration of the dataset values.
7
+ setting :default_enum_on, reader: true
8
+ option :enum_on, default: ->{ self.class.default_enum_on }
9
+
10
+ # Default query parameters
11
+ setting :default_params, EMPTY_HASH, reader: true
12
+ option :params, type: Types::Hash, default: ->{ self.class.default_params }
13
+
14
+ # Request and response handlers
15
+ config.default_response_handler = Response
16
+ config.default_request_handler = Request
17
+
18
+ # @override Handles multiple path segments and nils
19
+ def with_path(segments)
20
+ s = Array.wrap(segments)
21
+ return self if s.empty?
22
+ with_options(path: s.compact.join('/'))
23
+ end
24
+
25
+ def with_enum_on(keys)
26
+ k = Array.wrap(keys)
27
+ return self if k.empty?
28
+ with_options(enum_on: k)
29
+ end
30
+
31
+ # Coerce param value to an Array and set new value
32
+ # to set union with other Array of values.
33
+ def add_param_values(key, val)
34
+ new_val = Array.wrap(params[key]) | Array.wrap(val)
35
+ add_params(key => new_val)
36
+ end
37
+
38
+ # @override
39
+ def add_params(new_params = {})
40
+ return self if new_params.nil? || new_params.empty?
41
+ with_params params.merge(new_params).compact
42
+ end
43
+
44
+ def default_params(defaults = {})
45
+ with_params defaults.merge(params)
46
+ end
47
+
48
+ # @override Seems good to have no-op when params not changed?
49
+ def with_params(new_params)
50
+ if params == new_params
51
+ self
52
+ else
53
+ with_options(params: new_params)
54
+ end
55
+ end
56
+
57
+ def param?(key)
58
+ params.key?(key)
59
+ end
60
+
61
+ # Copies and makes private superclass #response method
62
+ alias_method :__response__, :response
63
+ private :__response__
64
+
65
+ # @override Cache response by default
66
+ def response
67
+ cache.fetch_or_store(:response) { __response__ }
68
+ end
69
+
70
+ # @override
71
+ def each(&block)
72
+ return to_enum unless block_given?
73
+ enumerable_response.each(&block)
74
+ end
75
+
76
+ def enumerable_response
77
+ if options[:enum_on].nil?
78
+ Array.wrap(response)
79
+ else
80
+ keys = Array.wrap options[:enum_on]
81
+ Array.wrap response.dig(*keys)
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def cache
88
+ @cache ||= Concurrent::Map.new
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,53 @@
1
+ module ROM
2
+ module Solr
3
+ class SelectDataset < Dataset
4
+
5
+ config.default_enum_on = [ 'response', 'docs' ]
6
+ config.default_params = { q: '*:*', start: 0, rows: 20, cursorMark: '*', sort: 'id ASC' }
7
+
8
+ # @override
9
+ def each
10
+ while true
11
+ enumerable_response.each { |doc| yield(doc) }
12
+ break if last_page?
13
+ update_cursor_mark
14
+ end
15
+ end
16
+
17
+ def num_found
18
+ response.dig('response', 'numFound')
19
+ end
20
+
21
+ def cursor_mark
22
+ params[:cursorMark]
23
+ end
24
+
25
+ def next_cursor_mark
26
+ response['nextCursorMark']
27
+ end
28
+
29
+ def page_size
30
+ params[:rows]
31
+ end
32
+
33
+ def last_cursor?
34
+ cursor_mark == next_cursor_mark
35
+ end
36
+
37
+ def one_page?
38
+ num_found <= page_size
39
+ end
40
+
41
+ def last_page?
42
+ one_page? || last_cursor?
43
+ end
44
+
45
+ private
46
+
47
+ def update_cursor_mark
48
+ add_params(cursorMark: next_cursor_mark)
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,25 @@
1
+ module ROM
2
+ module Solr
3
+ class Gateway < ROM::HTTP::Gateway
4
+
5
+ adapter :solr
6
+
7
+ def initialize(config = {})
8
+ config[:uri] ||= ENV.fetch('SOLR_URL', 'http://localhost:8983/solr')
9
+ config[:headers] ||= { Accept: 'application/json' }
10
+ super
11
+ end
12
+
13
+ def dataset(name)
14
+ dataset_class(name).new config.merge(base_path: name)
15
+ end
16
+
17
+ def dataset_class(name)
18
+ prefix = name.to_s.split(/_/).map(&:capitalize).join('')
19
+ const_name = "#{prefix}Dataset"
20
+ ROM::Solr.const_defined?(const_name, false) ? ROM::Solr.const_get(const_name, false) : Dataset
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,62 @@
1
+ module ROM
2
+ module Solr
3
+ class PaginatedDataset
4
+
5
+ attr_reader :dataset
6
+
7
+ def initialize(dataset)
8
+ ds = dataset
9
+ .default_params(rows: 20)
10
+ .remove_params(:start)
11
+ .add_params(cursorMark: '*')
12
+
13
+ if ds.param?(:sort)
14
+ unless ds.params[:sort] =~ /\bid\b/
15
+ ds = ds.sort('%{sort},id ASC' % ds.params)
16
+ end
17
+ else
18
+ ds = ds.sort('id ASC')
19
+ end
20
+
21
+ @dataset = ds
22
+ end
23
+
24
+ def each
25
+ while true
26
+ yield dataset
27
+ break if last_page?
28
+ @dataset = dataset.add_params(cursorMark: next_cursor_mark)
29
+ end
30
+ end
31
+
32
+ def cursor_mark
33
+ dataset.params[:cursorMark]
34
+ end
35
+
36
+ def next_cursor_mark
37
+ dataset.response['nextCursorMark']
38
+ end
39
+
40
+ def page_size
41
+ dataset.params[:rows]
42
+ end
43
+
44
+ def total_size
45
+ dataset.num_found
46
+ end
47
+
48
+ def last_cursor?
49
+ cursor_mark == next_cursor_mark
50
+ end
51
+
52
+ def one_page?
53
+ total_size <= page_size
54
+ end
55
+
56
+ def last_page?
57
+ one_page? || last_cursor?
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ module ROM
2
+ module Solr
3
+ class Relation < ROM::HTTP::Relation
4
+ extend Schemaless
5
+
6
+ adapter :solr
7
+
8
+ forward :add_param_values, :default_params, :with_enum_on
9
+
10
+ def fetch(key, default = nil)
11
+ return self if key.nil?
12
+ dataset.response.fetch(key, default)
13
+ end
14
+
15
+ def count
16
+ to_enum.count
17
+ end
18
+
19
+ def all
20
+ self
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,75 @@
1
+ module ROM
2
+ module Solr
3
+ class SchemaRelation < Relation
4
+
5
+ schemaless(:schema, as: :schema_info)
6
+
7
+ # GET /schema
8
+ def info
9
+ fetch('schema')
10
+ end
11
+
12
+ def schema_name
13
+ with_path(:name).fetch(:name)
14
+ end
15
+
16
+ def version
17
+ with_path('version').fetch('version')
18
+ end
19
+
20
+ def unique_key
21
+ with_path('uniquekey').fetch('uniqueKey')
22
+ end
23
+
24
+ def similarity
25
+ with_path('similarity').fetch('similarity')
26
+ end
27
+
28
+ # @param opts [Hash]
29
+ def fields(**opts)
30
+ default_opts = { showDefaults: true }
31
+ with_path('fields')
32
+ .with_enum_on('fields')
33
+ .add_params(default_opts.merge(opts))
34
+ end
35
+
36
+ # @param name [String, Symbol] field name
37
+ # @param opts [Hash]
38
+ def field(name, **opts)
39
+ with_path('fields', name)
40
+ .add_params(opts)
41
+ .fetch('field')
42
+ end
43
+
44
+ # @param opts [Hash]
45
+ def field_types(**opts)
46
+ with_path('fieldtypes')
47
+ .with_enum_on('fieldTypes')
48
+ .add_params(opts)
49
+ end
50
+
51
+ # @param name [String, Symbol] field type name
52
+ # @param opts [Hash]
53
+ def field_type(name, **opts)
54
+ with_path('fieldtypes', name).add_params(opts).fetch('fieldType')
55
+ end
56
+
57
+ # @param opts [Hash]
58
+ def dynamic_fields(**opts)
59
+ with_path('dynamicfields').with_enum_on('dynamicFields').add_params(opts)
60
+ end
61
+
62
+ # @param name [String, Symbol] dynamic field name
63
+ # @param opts [Hash]
64
+ def dynamic_field(name, **opts)
65
+ with_path('dynamicfields', name).add_params(opts).fetch('dynamicField')
66
+ end
67
+
68
+ # @param opts [Hash]
69
+ def copy_fields(**opts)
70
+ with_path('copyfields').with_enum_on('copyFields').add_params(opts)
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,43 @@
1
+ module ROM
2
+ module Solr
3
+ class SelectRelation < Relation
4
+
5
+ schemaless :select, as: :search
6
+
7
+ def filter(*fq)
8
+ add_param_values(:fq, fq)
9
+ end
10
+ alias_method :fq, :filter
11
+
12
+ def query(q)
13
+ add_params(q: q)
14
+ end
15
+ alias_method :q, :query
16
+
17
+ def fields(*fl)
18
+ add_params(fl: fl)
19
+ end
20
+ alias_method :fl, :fields
21
+
22
+ def start(offset)
23
+ add_params(start: offset.to_i)
24
+ end
25
+ alias_method :offset, :start
26
+
27
+ def rows(limit)
28
+ add_params(rows: limit.to_i)
29
+ end
30
+ alias_method :limit, :rows
31
+
32
+ def sort(crit)
33
+ add_params(sort: crit)
34
+ end
35
+
36
+ # @override Don't have to enumerate to get count (may not be exact)
37
+ def count
38
+ dataset.num_found
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,24 @@
1
+ module ROM
2
+ module Solr
3
+ class Request
4
+
5
+ def self.call(dataset)
6
+ uri = URI(dataset.uri)
7
+ uri.query = URI.encode_www_form(dataset.params)
8
+
9
+ http = Net::HTTP.new(uri.host, uri.port)
10
+ http.use_ssl = true if uri.scheme.eql?('https')
11
+
12
+ request_class = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))
13
+ request = request_class.new(uri.request_uri)
14
+
15
+ dataset.headers.each_with_object(request) do |(header, value), request|
16
+ request[header.to_s] = value
17
+ end
18
+
19
+ http.request(request)
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ module ROM
2
+ module Solr
3
+ class Response
4
+
5
+ # @return [Hash] Parsed JSON object from Solr response body
6
+ def self.call(response, dataset)
7
+ JSON.parse(response.body)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module ROM
2
+ module Solr
3
+ class Schema < ROM::HTTP::Schema
4
+
5
+
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ require "hashie"
2
+
3
+ module ROM
4
+ module Solr
5
+ module Schemaless
6
+
7
+ def self.extended(base)
8
+ schemaless_output = Class.new(Hashie::Mash) do
9
+ include Hashie::Extensions::Mash::SymbolizeKeys
10
+ disable_warnings
11
+ end
12
+ base.const_set(:SchemalessOutput, schemaless_output)
13
+ base.option :output_schema, default: ->{ self.class.const_get(:SchemalessOutput) }
14
+ end
15
+
16
+ def schemaless(*args)
17
+ schema(*args) do
18
+ # no schema :)
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -1,32 +1,39 @@
1
1
  require "solrbee/version"
2
- require "solrbee/api_methods"
3
- require "solrbee/query"
4
- require "solrbee/cursor"
5
- require "solrbee/client"
2
+ require "solrbee/array"
3
+ require "rom/solr"
6
4
 
7
5
  module Solrbee
8
6
 
9
- class Error < StandardError; end
7
+ # Factory method
8
+ #
9
+ # @return [ROM::Solr::Gateway] a gateway instance
10
+ def self.gateway
11
+ ROM::Gateway.setup(:solr)
12
+ end
10
13
 
11
- API_VERSION = 'V1'
14
+ # Factory method
15
+ #
16
+ # @return [Solrbee::Documents] a ROM relation for searching
17
+ def self.documents
18
+ container.relations[:search]
19
+ end
12
20
 
13
- # Single-valued field types
14
- STRING = "string"
15
- LONG = "plong"
16
- INT = "pint"
17
- DATE = "pdate"
18
- BOOLEAN = "boolean"
21
+ def self.schema
22
+ container.relations[:schema_info]
23
+ end
19
24
 
20
- # Multi-valued field types
21
- MSTRING = "strings"
22
- MLONG = "plongs"
23
- MINT = "pints"
24
- MDATE = "pdates"
25
- MBOOLEAN = "booleans"
25
+ # @return [ROM::Configuration] configuration
26
+ def self.config
27
+ @config ||= ROM::Configuration.new(:solr) do |config|
28
+ config.register_relation(
29
+ ROM::Solr::SelectRelation,
30
+ ROM::Solr::SchemaRelation
31
+ )
32
+ end
33
+ end
26
34
 
27
- # Base URL
28
- def self.solr_url
29
- ENV.fetch('SOLR_URL', 'http://localhost:8983/solr').sub(/\/\z/, '')
35
+ def self.container
36
+ ROM.container(config)
30
37
  end
31
38
 
32
39
  end
@@ -0,0 +1,10 @@
1
+ Array.class_eval do
2
+
3
+ # Inspired by Rails's Array.wrap
4
+ def self.wrap(obj)
5
+ return [] if obj.nil?
6
+ return obj.to_ary if obj.respond_to?(:to_ary)
7
+ Array.new(1, obj)
8
+ end
9
+
10
+ end
@@ -1,3 +1,3 @@
1
1
  module Solrbee
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "hashie"
26
+ spec.add_dependency "rom"
27
+ spec.add_dependency "rom-http"
26
28
 
27
29
  spec.add_development_dependency "bundler"
28
30
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solrbee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Chandek-Stark
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-12-14 00:00:00.000000000 Z
11
+ date: 2020-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rom
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rom-http
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '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'
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -96,11 +124,21 @@ files:
96
124
  - Rakefile
97
125
  - bin/console
98
126
  - bin/setup
127
+ - config/api.yml
128
+ - lib/rom/solr.rb
129
+ - lib/rom/solr/dataset.rb
130
+ - lib/rom/solr/datasets/select_dataset.rb
131
+ - lib/rom/solr/gateway.rb
132
+ - lib/rom/solr/paginated_dataset.rb
133
+ - lib/rom/solr/relation.rb
134
+ - lib/rom/solr/relations/schema_relation.rb
135
+ - lib/rom/solr/relations/select_relation.rb
136
+ - lib/rom/solr/request.rb
137
+ - lib/rom/solr/response.rb
138
+ - lib/rom/solr/schema.rb
139
+ - lib/rom/solr/schemaless.rb
99
140
  - lib/solrbee.rb
100
- - lib/solrbee/api_methods.rb
101
- - lib/solrbee/client.rb
102
- - lib/solrbee/cursor.rb
103
- - lib/solrbee/query.rb
141
+ - lib/solrbee/array.rb
104
142
  - lib/solrbee/version.rb
105
143
  - solrbee.gemspec
106
144
  homepage: https://github.com/dchandekstark/solrbee
@@ -1,94 +0,0 @@
1
- module Solrbee
2
- module ApiMethods
3
-
4
- def ping
5
- response = request(path: '/admin/ping')
6
- response['status']
7
- end
8
-
9
- def schema
10
- response = request(path: '/schema')
11
- response['schema']
12
- end
13
-
14
- def schema_name
15
- response = request(path: '/schema/name')
16
- response['name']
17
- end
18
-
19
- def schema_version
20
- response = request(path: '/schema/version')
21
- response['version']
22
- end
23
-
24
- def fields(**params)
25
- response = request(path: '/schema/fields', params: params)
26
- response['fields']
27
- end
28
-
29
- def field(field_name, **params)
30
- response = request(path: '/schema/fields/%s' % field_name, params: params)
31
- response['field']
32
- end
33
-
34
- def unique_key
35
- response = request(path: '/schema/uniquekey')
36
- response['uniqueKey']
37
- end
38
-
39
- def field_types(**params)
40
- response = request(path: '/schema/fieldtypes', params: params)
41
- response['fieldTypes']
42
- end
43
-
44
- def field_type(field_name, **params)
45
- response = request(path: '/schema/fieldtypes/%s' % field_name, params: params)
46
- response['fieldType']
47
- end
48
-
49
- def field_names
50
- fields.map { |f| f['name'] }
51
- end
52
-
53
- def field_type_names
54
- field_types.map { |f| f['name'] }
55
- end
56
-
57
- def modify_schema(commands)
58
- request(path: '/schema', data: commands)
59
- end
60
-
61
- def add_field(field)
62
- modify_schema("add-field"=>field)
63
- end
64
-
65
- def delete_field(field_name)
66
- modify_schema("delete-field"=>{"name"=>field_name})
67
- end
68
-
69
- def replace_field(field)
70
- modify_schema("replace-field"=>field)
71
- end
72
-
73
- # "real-time get"
74
- def get_by_id(*ids, **params)
75
- response = request(path: '/get', params: params.merge(id: ids.join(',')))
76
- response['response']['doc'] || response['response']['docs']
77
- end
78
-
79
- def index(*docs, **params)
80
- request(path: '/update/json/docs', data: docs, params: params)
81
- end
82
- alias_method :add, :index
83
- alias_method :update, :index
84
-
85
- def delete(*ids)
86
- request(path: '/update', data: { delete: ids })
87
- end
88
-
89
- def query(**params)
90
- request(path: '/query', data: params)
91
- end
92
-
93
- end
94
- end
@@ -1,50 +0,0 @@
1
- require "net/http"
2
- require "uri"
3
- require "json"
4
-
5
- module Solrbee
6
- class Client
7
- include ApiMethods
8
-
9
- attr_reader :uri
10
-
11
- def self.cursor(url: nil)
12
- new(url: url).cursor
13
- end
14
-
15
- def initialize(url: nil)
16
- @uri = URI(url || ENV['SOLR_URL'])
17
- end
18
-
19
- def connection
20
- Net::HTTP.new(uri.host, uri.port).tap do |http|
21
- http.use_ssl = true if uri.scheme == 'https'
22
- end
23
- end
24
-
25
- def cursor
26
- Cursor.new(self)
27
- end
28
-
29
- def request(path:, data: nil, params: {})
30
- req_class = data ? Net::HTTP::Post : Net::HTTP::Get
31
-
32
- req_uri = uri.dup.tap do |u|
33
- u.path += path
34
- u.query = URI.encode_www_form(params) unless params.empty?
35
- end
36
-
37
- req = req_class.new(req_uri)
38
- req['Accept'] = 'application/json'
39
-
40
- if data
41
- req['Content-Type'] = 'application/json'
42
- req.body = JSON.dump(data)
43
- end
44
-
45
- http_response = connection.request(req)
46
- JSON.parse(http_response.body)
47
- end
48
-
49
- end
50
- end
@@ -1,37 +0,0 @@
1
- module Solrbee
2
- #
3
- # SUMMARY
4
- #
5
- # > client = Solrbee::Client.new
6
- # > cursor = Solrbee::Cursor.new(client)
7
- # > query = { query: 'foo:bar', sort: 'title ASC', limit: 10 }
8
- # > results = cursor.execute(query)
9
- # > results.each do |doc|
10
- # ...
11
- # > end
12
- #
13
- class Cursor
14
-
15
- attr_reader :client
16
-
17
- def initialize(client)
18
- @client = client
19
- end
20
-
21
- # @return [Enumerator] an enumerator of query results
22
- def execute(query)
23
- Enumerator.new do |yielder|
24
- q = Query.cursor(query, client.unique_key)
25
-
26
- while true
27
- response = client.query(q)
28
- break if response['response']['numFound'] == 0
29
- break if response['nextCursorMark'] == q.params.cursorMark
30
- response['response']['docs'].each { |doc| yielder << doc }
31
- q.params.cursorMark = response['nextCursorMark']
32
- end
33
- end
34
- end
35
-
36
- end
37
- end
@@ -1,35 +0,0 @@
1
- require 'hashie'
2
-
3
- module Solrbee
4
- #
5
- # A query targeting the JSON Request API.
6
- #
7
- class Query < Hashie::Trash
8
- property :query, from: :q, default: '*:*'
9
- property :filter, from: :fq
10
- property :limit, from: :rows, default: 10
11
- property :fields, from: :fl
12
- property :sort
13
- property :offset, from: :start
14
- property :facet
15
- property :queries
16
- property :params, default: {}
17
-
18
- # Build a query for a Cursor
19
- def self.cursor(params, unique_key)
20
- Query.new(params).tap do |q|
21
- q.delete(:offset) # incompatible with cursor
22
- q.params[:cursorMark] = '*' # initial cursor mark
23
-
24
- # Sort on unique key is required for cursor
25
- q.sort = "#{unique_key} ASC" unless q.sort
26
- unless q.sort =~ /\b#{unique_key}\b/
27
- clauses = q.sort.split(/,/)
28
- clauses << "#{unique_key} ASC"
29
- q.sort = clauses.join(',')
30
- end
31
- end
32
- end
33
-
34
- end
35
- end