solrbee 0.1.1 → 0.4.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: 77127390eb03bfbd53eec6916f7873fab49b6436f4acb94c528f2cec7ed5f76b
4
- data.tar.gz: '08ab2300881e0fdacaafa0007d1a17031a2b11bebfe2ade9cbf533a02a7b2b42'
3
+ metadata.gz: 11deb067a219ff325c0aa6dfaeb14422674cfd2a30338d14a1f00fa3f2081550
4
+ data.tar.gz: b6566f900e8a437feb379dba1e7f8de64e9c5a4b821cc501256ce0ee58da52e1
5
5
  SHA512:
6
- metadata.gz: 5642a45f1013a4ddf33f4a339f0990ec218d7c3ebce3e6b3e1a0811c81256a6c155df333d7894618de9cb4a8b9e7c9eac5f178237474e96cd2de5ec7193cee83
7
- data.tar.gz: bba5257728a581433cf72dbd4dce18ab5f8f7baea95afca7dca75c16f5fc17b509110c9e8ecb9a87713960f3eccf951d0bf11a0afe8b4ba01de2f331fcefd095
6
+ metadata.gz: aa65e21c6552dc4d4276ecfdc1a4089e69d3625af84d014cb6353183a9e145ed8adf34158b180e2c70d1718d211e35b32fbd545438bd13753d171484b1577010
7
+ data.tar.gz: 78fd833f50640f5f875be47160a87642f2b612c90906e3d349e68042f5d267b4b375727babcc8c2512c90006e7e858535e2382ecfc638d7dff333822f20e04c4
data/Gemfile CHANGED
@@ -1,3 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
+
5
+ gem 'rom', '5.2.4'
6
+ gem 'rom-http', git: 'https://github.com/rom-rb/rom-http.git'
data/Makefile CHANGED
@@ -2,13 +2,4 @@ SHELL = /bin/bash
2
2
 
3
3
  .PHONY : test
4
4
  test:
5
- bundle exec rake
6
-
7
-
8
- .PHONY : start-test-server
9
- start-test-server:
10
- docker run --rm -d -p 8983:8983 --name solrbee-test solr:8 solr-precreate solrbee
11
-
12
- .PHONY : stop-test-server
13
- stop-test-server:
14
- docker stop solrbee-test
5
+ ./test.sh
data/README.md CHANGED
@@ -25,7 +25,7 @@ Or install it yourself as:
25
25
 
26
26
  ## Usage
27
27
 
28
-
28
+ TODO
29
29
 
30
30
  ## Development
31
31
 
@@ -0,0 +1,22 @@
1
+ field_types:
2
+ path: fieldtypes
3
+ key: fieldTypes
4
+ field_type:
5
+ desc: GET /schema/fieldtype/[name]
6
+ path: fieldtypes/%{name}
7
+ args:
8
+ - name
9
+ key: fieldType
10
+ dynamic_fields:
11
+ desc: GET /schema/dynamicfields
12
+ path: dynamicfields
13
+ key: dynamicFields
14
+ dynamic_field:
15
+ desc: GET /schema/dynamicfields/[name]
16
+ args:
17
+ - name
18
+ path: dynamicfields/%{name}
19
+ key: dynamicField
20
+ copy_fields:
21
+ path: copyfields
22
+ key: copyFields
@@ -0,0 +1,51 @@
1
+ require 'rom-http'
2
+ require 'securerandom'
3
+
4
+ module ROM
5
+ module Solr
6
+
7
+ def self.dataset_class(name)
8
+ prefix = name.to_s.split(/[_\/]/).map(&:capitalize).join('')
9
+ const_name = "#{prefix}Dataset"
10
+ const_defined?(const_name, false) ? const_get(const_name, false) : Dataset
11
+ end
12
+
13
+ module Types
14
+ include ROM::HTTP::Types
15
+ end
16
+
17
+ UUID = Types::String.default { SecureRandom.uuid }
18
+
19
+ end
20
+ end
21
+
22
+ # Utilities
23
+ require_relative 'solr/array'
24
+
25
+ # Handlers
26
+ require_relative 'solr/request_handler'
27
+ require_relative 'solr/response_handler'
28
+
29
+ # Datasets
30
+ require_relative 'solr/dataset'
31
+ require_relative 'solr/documents_dataset'
32
+ require_relative 'solr/schema_info_dataset'
33
+
34
+ # Gateway
35
+ require_relative 'solr/gateway'
36
+
37
+ # Schemas
38
+ require_relative 'solr/schema'
39
+
40
+ # Relations
41
+ require_relative 'solr/relation'
42
+
43
+ # Repositories
44
+ require_relative 'solr/repository'
45
+ require_relative 'solr/schema_info_repo'
46
+ require_relative 'solr/document_repo'
47
+
48
+ # Commands
49
+ require_relative 'solr/commands'
50
+
51
+ ROM.register_adapter(:solr, ROM::Solr)
@@ -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
@@ -0,0 +1,17 @@
1
+ module ROM
2
+ module Solr
3
+ module Commands
4
+ class Create < ROM::Commands::Create
5
+ adapter :solr
6
+ end
7
+
8
+ class Update < ROM::Commands::Update
9
+ adapter :solr
10
+ end
11
+
12
+ class Delete < ROM::Commands::Delete
13
+ adapter :solr
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module ROM
2
+ module Solr
3
+ module Commands
4
+ class CreateDocuments < Create
5
+
6
+ relation :documents
7
+
8
+ def execute(docs)
9
+ relation.insert(docs)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ROM
2
+ module Solr
3
+ module Commands
4
+ class DeleteDocuments < Delete
5
+
6
+ relation :documents
7
+
8
+ def execute(docs)
9
+ relation.delete(docs)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ROM
2
+ module Solr
3
+ module Commands
4
+ class DeleteDocumentsByQuery < Delete
5
+
6
+ relation :documents
7
+
8
+ def execute(query)
9
+ relation.delete_by_query(query).response
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ROM
2
+ module Solr
3
+ module Commands
4
+ class UpdateDocuments < Update
5
+
6
+ relation :documents
7
+
8
+ def execute(docs)
9
+ relation.update(docs)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,72 @@
1
+ module ROM
2
+ module Solr
3
+ class Dataset < ROM::HTTP::Dataset
4
+
5
+ setting :default_response_key, reader: true
6
+ setting :default_content_type, reader: true
7
+ setting :default_base_path, reader: true
8
+
9
+ configure do |config|
10
+ config.default_response_handler = ResponseHandler
11
+ config.default_request_handler = RequestHandler
12
+ end
13
+
14
+ option :response_key, default: proc { self.class.default_response_key }
15
+ option :request_data, type: Types::String, default: proc { EMPTY_STRING }
16
+ option :content_type, type: Types::String, default: proc { self.class.default_content_type }
17
+ option :base_path, type: Types::Path, default: proc { self.class.default_base_path || EMPTY_STRING }
18
+
19
+ # @override Query parameters are valid with POST, too.
20
+ def uri
21
+ uri_s = [options[:uri], path].compact.reject(&:empty?).join('/')
22
+
23
+ URI(uri_s).tap do |u|
24
+ u.query = param_encoder.call(params) if has_params?
25
+ end
26
+ end
27
+
28
+ # @override
29
+ def each(&block)
30
+ return to_enum unless block_given?
31
+
32
+ enumerable_data.each(&block)
33
+ end
34
+
35
+ def with_request_data(data)
36
+ with_options(request_data: data)
37
+ end
38
+
39
+ def with_response_key(*path)
40
+ with_options(response_key: path)
41
+ end
42
+
43
+ # Copies and makes private superclass #response method
44
+ alias_method :__response__, :response
45
+ private :__response__
46
+
47
+ # @override Cache response by default
48
+ def response
49
+ cache.fetch_or_store(:response) { __response__ }
50
+ end
51
+
52
+ def has_request_data?
53
+ !request_data.nil? && !request_data.empty?
54
+ end
55
+
56
+ def has_params?
57
+ params.any?
58
+ end
59
+
60
+ private
61
+
62
+ def enumerable_data
63
+ Array.wrap(response_key ? response.dig(*response_key) : response)
64
+ end
65
+
66
+ def cache
67
+ @cache ||= Concurrent::Map.new
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,33 @@
1
+ module ROM
2
+ module Solr
3
+ class DocumentRepo < Repository[:documents]
4
+
5
+ auto_struct false
6
+
7
+ def find(id)
8
+ documents.by_unique_key(id).one!
9
+ end
10
+
11
+ def search
12
+ documents
13
+ end
14
+
15
+ def all
16
+ documents.all
17
+ end
18
+
19
+ def create(docs)
20
+ documents.command(:create_documents).call(docs)
21
+ end
22
+
23
+ def delete(docs)
24
+ documents.command(:delete_documents).call(docs)
25
+ end
26
+
27
+ def update(docs)
28
+ documents.command(:update_documents).call(docs)
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ module ROM
2
+ module Solr
3
+ class DocumentsDataset < Dataset
4
+
5
+ configure do |config|
6
+ config.default_response_key = [:response, :docs]
7
+ config.default_base_path = 'select'
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module ROM
2
+ module Solr
3
+ class Gateway < ROM::HTTP::Gateway
4
+
5
+ adapter :solr
6
+
7
+ # @override
8
+ def dataset(name)
9
+ ROM::Solr.dataset_class(name).new(config)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ module ROM
2
+ module Solr
3
+ class Relation < ROM::HTTP::Relation
4
+
5
+ adapter :solr
6
+ auto_struct false
7
+ auto_map false
8
+
9
+ forward :with_response_key
10
+
11
+ option :output_schema, default: ->{ NOOP_OUTPUT_SCHEMA }
12
+
13
+ def wt(format)
14
+ add_params(wt: Types::Coercible::String[format])
15
+ end
16
+ alias_method :format, :wt
17
+
18
+ def log_params_list(log_params)
19
+ lplist = log_params.nil? ? nil : Array.wrap(log_params).join(',')
20
+
21
+ add_params(logParamsList: lplist)
22
+ end
23
+ alias_method :log_params, :log_params_list
24
+
25
+ def count
26
+ to_enum.count
27
+ end
28
+
29
+ def response
30
+ dataset.response
31
+ end
32
+
33
+ def params
34
+ dataset.params.dup
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,160 @@
1
+ require 'rom/solr/select_cursor'
2
+
3
+ module ROM
4
+ module Solr
5
+ class DocumentsRelation < Relation
6
+
7
+ schema(:documents) { }
8
+
9
+ # @override
10
+ def each(&block)
11
+ return to_enum unless block_given?
12
+
13
+ SelectCursor.new(dataset).each(&block)
14
+ end
15
+
16
+ # @override FIXME: Get from Solr schema unique key
17
+ def primary_key
18
+ :id
19
+ end
20
+
21
+ def by_unique_key(id)
22
+ q('%s:%s' % [ primary_key, id ])
23
+ end
24
+
25
+ def all
26
+ q('*:*')
27
+ end
28
+
29
+ # @override
30
+ def count
31
+ num_found_exact ? num_found : super
32
+ end
33
+
34
+ def num_found
35
+ response.dig(:response, :numFound)
36
+ end
37
+
38
+ def num_found_exact
39
+ response.dig(:response, :numFoundExact)
40
+ end
41
+
42
+ def insert(docs)
43
+ data = Array.wrap(docs).map do |doc|
44
+ doc.transform_keys!(&:to_sym)
45
+ doc[:id] ||= UUID[]
46
+ end
47
+
48
+ update(data)
49
+ end
50
+
51
+ def update(docs)
52
+ with_options(
53
+ base_path: 'update/json/docs',
54
+ content_type: 'application/json',
55
+ request_data: JSON.dump(docs)
56
+ )
57
+ end
58
+
59
+ def delete(docs)
60
+ ids = Array.wrap(docs).map { |doc| doc.transform_keys(&:to_sym) }.map(&:id)
61
+
62
+ with_options(
63
+ base_path: 'update',
64
+ content_type: 'application/json',
65
+ request_data: JSON.dump(delete: ids)
66
+ )
67
+ end
68
+
69
+ #
70
+ # Params
71
+ #
72
+ def q(query)
73
+ add_params(q: Types::String[query])
74
+ end
75
+ alias_method :query, :q
76
+
77
+ def fq(*filter)
78
+ add_params(fq: filter)
79
+ end
80
+ alias_method :filter, :fq
81
+
82
+ def fl(*fields)
83
+ add_params(fl: fields.join(','))
84
+ end
85
+ alias_method :fields, :fl
86
+
87
+ def cache(enabled = true)
88
+ add_params(cache: Types::Bool[enabled])
89
+ end
90
+
91
+ def segment_terminate_early(enabled = true)
92
+ add_params(segmentTerminateEarly: Types::Bool[enabled])
93
+ end
94
+
95
+ def time_allowed(millis)
96
+ add_params(timeAllowed: Types::Coercible::Integer[millis])
97
+ end
98
+
99
+ def explain_other(query)
100
+ add_params(explainOther: Types::String[query])
101
+ end
102
+
103
+ def omit_header(omit = true)
104
+ add_params(omitHeader: Types::Bool[omit])
105
+ end
106
+
107
+ def start(offset)
108
+ add_params(start: Types::Coercible::Integer[offset])
109
+ end
110
+
111
+ def sort(*criteria)
112
+ add_params(sort: criteria.join(','))
113
+ end
114
+
115
+ def rows(num)
116
+ add_params(rows: Types::Coercible::Integer[num])
117
+ end
118
+ alias_method :limit, :rows
119
+
120
+ def def_type(value)
121
+ add_params(defType: Types::Coercible::String[value])
122
+ end
123
+
124
+ def debug(setting)
125
+ type = Types::Coercible::String
126
+ .enum('query', 'timing', 'results', 'all', 'true')
127
+
128
+ add_params(debug: type[setting])
129
+ end
130
+
131
+ def echo_params(setting)
132
+ type = Types::Coercible::String.enum('explicit', 'all', 'none')
133
+ add_params(echoParams: type[setting])
134
+ end
135
+
136
+ def min_exact_count(num)
137
+ add_params(minExactCount: Types::Coercible::Integer[num])
138
+ end
139
+
140
+ def commit(value = true)
141
+ add_params(commit: Types::Bool[value])
142
+ end
143
+
144
+ def commit_within(millis)
145
+ return self if millis.nil?
146
+
147
+ add_params(commitWithin: Types::Coercible::Integer[millis])
148
+ end
149
+
150
+ def overwrite(value = true)
151
+ add_params(overwrite: Types::Bool[value])
152
+ end
153
+
154
+ def expunge_deletes(value = true)
155
+ add_params(expungeDeletes: Types::Bool[value])
156
+ end
157
+
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,100 @@
1
+ module ROM
2
+ module Solr
3
+ class SchemaInfoRelation < Relation
4
+
5
+ schema(:schema_info) do
6
+ # no-op
7
+ end
8
+
9
+ def show_defaults(show = true)
10
+ add_params(showDefaults: Types::Bool[show])
11
+ end
12
+
13
+ def include_dynamic(enabled = true)
14
+ add_params(includeDynamic: Types::Bool[enabled])
15
+ end
16
+
17
+ def info
18
+ with_response_key(:schema)
19
+ end
20
+
21
+ def copy_fields
22
+ with_options(
23
+ path: :copyfields,
24
+ response_key: :copyFields
25
+ )
26
+ end
27
+
28
+ def dynamic_fields
29
+ with_options(
30
+ path: :dynamicfields,
31
+ response_key: :dynamicFields
32
+ )
33
+ end
34
+
35
+ def dynamic_field(name)
36
+ with_options(
37
+ path: "dynamicfields/#{name}",
38
+ response_key: :dynamicField
39
+ )
40
+ end
41
+
42
+ def similarity
43
+ with_options(
44
+ path: :similarity,
45
+ response_key: :similarity
46
+ )
47
+ end
48
+
49
+ def unique_key
50
+ with_options(
51
+ path: :uniquekey,
52
+ response_key: :uniqueKey
53
+ )
54
+ end
55
+
56
+ def version
57
+ with_options(
58
+ path: :version,
59
+ response_key: :version
60
+ )
61
+ end
62
+
63
+ def schema_name
64
+ with_options(
65
+ path: :name,
66
+ response_key: :name
67
+ )
68
+ end
69
+
70
+ def fields
71
+ with_options(
72
+ path: :fields,
73
+ response_key: :fields
74
+ )
75
+ end
76
+
77
+ def field(name)
78
+ with_options(
79
+ path: "fields/#{name}",
80
+ response_key: :field
81
+ )
82
+ end
83
+
84
+ def field_types
85
+ with_options(
86
+ path: :fieldtypes,
87
+ response_key: :fieldTypes
88
+ )
89
+ end
90
+
91
+ def field_type(name)
92
+ with_options(
93
+ path: "fieldtypes/#{name}",
94
+ response_key: :fieldType
95
+ )
96
+ end
97
+
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,9 @@
1
+ module ROM
2
+ module Solr
3
+ class Repository < ROM::Repository
4
+
5
+ auto_struct false
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ module ROM
2
+ module Solr
3
+ class RequestHandler
4
+
5
+ def self.call(dataset)
6
+ new(dataset).execute
7
+ end
8
+
9
+ attr_reader :dataset
10
+
11
+ def initialize(dataset)
12
+ @dataset = dataset
13
+ end
14
+
15
+ def execute
16
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme.eql?('https')) do |http|
17
+ http.request(request)
18
+ end
19
+ end
20
+
21
+ def request
22
+ request_class.new(uri.request_uri, headers).tap do |req|
23
+ if dataset.has_request_data?
24
+ req.body = dataset.request_data
25
+ req.content_type = dataset.content_type
26
+ end
27
+ end
28
+ end
29
+
30
+ def headers
31
+ dataset.headers.transform_keys(&:to_s)
32
+ end
33
+
34
+ def uri
35
+ @uri ||= URI(dataset.uri).tap do |u|
36
+ if dataset.has_params?
37
+ u.query ||= URI.encode_www_form(dataset.params)
38
+ end
39
+ end
40
+ end
41
+
42
+ def request_class
43
+ if dataset.has_request_data?
44
+ Net::HTTP::Post
45
+ else
46
+ Net::HTTP::Get
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,12 @@
1
+ module ROM
2
+ module Solr
3
+ class ResponseHandler
4
+
5
+ # @return [Hash] Parsed JSON object from Solr response body
6
+ def self.call(response, dataset)
7
+ JSON.parse(response.body, symbolize_names: true)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module ROM
2
+ module Solr
3
+ class Schema < ROM::Schema
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module ROM
2
+ module Solr
3
+ class SchemaInfoDataset < Dataset
4
+
5
+ configure do |config|
6
+ config.default_base_path = 'schema'
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module ROM
2
+ module Solr
3
+ class SchemaInfoRepo < Repository[:schema_info]
4
+
5
+ auto_struct false
6
+
7
+ %i[ schema_name similarity unique_key version ].each do |name|
8
+ define_method name, ->{ schema_info.send(name).one! }
9
+ end
10
+
11
+ def info
12
+ schema_info.info.one!
13
+ end
14
+
15
+ def fields(dynamic: true, defaults: true)
16
+ schema_info.fields.show_defaults(defaults).include_dynamic(dynamic)
17
+ end
18
+
19
+ def field(name, defaults: true)
20
+ schema_info.field(name).show_defaults(defaults).one
21
+ end
22
+
23
+ def field_types(defaults: true)
24
+ schema_info.field_types.show_defaults(defaults)
25
+ end
26
+
27
+ def field_type(name, defaults: true)
28
+ schema_info.field_type(name).show_defaults(defaults).one
29
+ end
30
+
31
+ def dynamic_fields
32
+ schema_info.dynamic_fields
33
+ end
34
+
35
+ def dynamic_field(name, defaults: true)
36
+ schema_info.dynamic_field(name).show_defaults(defaults).one
37
+ end
38
+
39
+ def copy_fields
40
+ schema_info.copy_fields
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,56 @@
1
+ require 'delegate'
2
+
3
+ module ROM
4
+ module Solr
5
+ #
6
+ # Wraps a DocumentsDataset to provide pagination with a cursor.
7
+ #
8
+ class SelectCursor < SimpleDelegator
9
+
10
+ def initialize(dataset)
11
+ params = { cursorMark: '*' }
12
+
13
+ # Sort must include a sort on unique key (id).
14
+ sort = dataset.params[:sort]
15
+ unless /\bid\b/ =~ sort
16
+ params[:sort] = Array.wrap(sort).append('id ASC').join(',')
17
+ end
18
+
19
+ super dataset.add_params(params)
20
+ end
21
+
22
+ def each(&block)
23
+ return to_enum unless block_given?
24
+
25
+ while true
26
+ __getobj__.each(&block)
27
+
28
+ break if last_page?
29
+
30
+ move_cursor
31
+ end
32
+ end
33
+
34
+ def cursor_mark
35
+ params[:cursorMark]
36
+ end
37
+
38
+ def next_cursor_mark
39
+ response[:nextCursorMark]
40
+ end
41
+
42
+ def last_page?
43
+ cursor_mark == next_cursor_mark
44
+ end
45
+
46
+ def move_cursor
47
+ __setobj__(next_page)
48
+ end
49
+
50
+ def next_page
51
+ __getobj__.add_params(cursorMark: next_cursor_mark)
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -1,31 +1,28 @@
1
1
  require "solrbee/version"
2
- require "solrbee/response"
3
- require "solrbee/request_params"
4
- require "solrbee/query"
5
- require "solrbee/client"
6
- require "solrbee/cursor"
2
+
3
+ require "rom/solr"
7
4
 
8
5
  module Solrbee
9
6
 
10
- class Error < StandardError; end
11
-
12
- # Single-valued field types
13
- STRING = "string"
14
- LONG = "plong"
15
- INT = "pint"
16
- DATE = "pdate"
17
- BOOLEAN = "boolean"
18
-
19
- # Multi-valued field types
20
- MSTRING = "strings"
21
- MLONG = "plongs"
22
- MINT = "pints"
23
- MDATE = "pdates"
24
- MBOOLEAN = "booleans"
25
-
26
- # Base URL
27
- def self.solr_url
28
- ENV.fetch('SOLR_URL', 'http://localhost:8983/solr').sub(/\/\z/, '')
7
+ DEFAULT_URI = ENV.fetch('SOLR_URL', 'http://localhost:8983/solr').freeze
8
+
9
+ def self.documents
10
+ ROM::Solr::DocumentRepo.new(container)
11
+ end
12
+
13
+ def self.schema_info
14
+ ROM::Solr::SchemaInfoRepo.new(container)
15
+ end
16
+
17
+ def self.container(uri: DEFAULT_URI)
18
+ ROM.container(:solr, uri: uri) do |config|
19
+ config.auto_registration(
20
+ File.expand_path('../rom/solr/', __FILE__),
21
+ namespace: 'ROM::Solr'
22
+ )
23
+
24
+ yield config if block_given?
25
+ end
29
26
  end
30
27
 
31
28
  end
@@ -1,3 +1,3 @@
1
1
  module Solrbee
2
- VERSION = "0.1.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -22,7 +22,8 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "hashie"
25
+ spec.add_dependency "rom"
26
+ spec.add_dependency "rom-http"
26
27
 
27
28
  spec.add_development_dependency "bundler"
28
29
  spec.add_development_dependency "rake"
data/test.sh ADDED
@@ -0,0 +1,14 @@
1
+ #!/bin/bash
2
+
3
+ docker run --rm -d -p 8983:8983 --name solrbee-test solr:8 solr-precreate solrbee
4
+
5
+ while ! curl -fs http://localhost:8983/solr/solrbee/admin/ping 2>/dev/null ;
6
+ do sleep 1
7
+ done
8
+
9
+ SOLR_URL=http://localhost:8983/solr/solrbee bundle exec rake
10
+ code=$?
11
+
12
+ docker stop solrbee-test
13
+
14
+ exit $code
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solrbee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.4.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-04 00:00:00.000000000 Z
11
+ date: 2020-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: hashie
14
+ name: rom
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rom-http
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - ">="
@@ -96,15 +110,32 @@ files:
96
110
  - Rakefile
97
111
  - bin/console
98
112
  - bin/setup
113
+ - config/api.yml
114
+ - lib/rom/solr.rb
115
+ - lib/rom/solr/array.rb
116
+ - lib/rom/solr/commands.rb
117
+ - lib/rom/solr/commands/create_documents.rb
118
+ - lib/rom/solr/commands/delete_documents.rb
119
+ - lib/rom/solr/commands/delete_documents_by_query.rb
120
+ - lib/rom/solr/commands/update_documents.rb
121
+ - lib/rom/solr/dataset.rb
122
+ - lib/rom/solr/document_repo.rb
123
+ - lib/rom/solr/documents_dataset.rb
124
+ - lib/rom/solr/gateway.rb
125
+ - lib/rom/solr/relation.rb
126
+ - lib/rom/solr/relations/documents_relation.rb
127
+ - lib/rom/solr/relations/schema_info_relation.rb
128
+ - lib/rom/solr/repository.rb
129
+ - lib/rom/solr/request_handler.rb
130
+ - lib/rom/solr/response_handler.rb
131
+ - lib/rom/solr/schema.rb
132
+ - lib/rom/solr/schema_info_dataset.rb
133
+ - lib/rom/solr/schema_info_repo.rb
134
+ - lib/rom/solr/select_cursor.rb
99
135
  - lib/solrbee.rb
100
- - lib/solrbee/api_methods.rb
101
- - lib/solrbee/client.rb
102
- - lib/solrbee/cursor.rb
103
- - lib/solrbee/query.rb
104
- - lib/solrbee/request_params.rb
105
- - lib/solrbee/response.rb
106
136
  - lib/solrbee/version.rb
107
137
  - solrbee.gemspec
138
+ - test.sh
108
139
  homepage: https://github.com/dchandekstark/solrbee
109
140
  licenses:
110
141
  - MIT
@@ -1,85 +0,0 @@
1
- module Solrbee
2
- module ApiMethods
3
-
4
- def schema_name
5
- response = get('/schema/name')
6
- response.name
7
- end
8
-
9
- def schema_version
10
- response = get('/schema/version')
11
- response.version
12
- end
13
-
14
- def schema
15
- response = get('/schema')
16
- response.schema
17
- end
18
-
19
- def fields(**params)
20
- response = get('/schema/fields', **params)
21
- response.fields
22
- end
23
-
24
- def field(field_name, **params)
25
- response = get('/schema/fields/%s' % field_name, **params)
26
- response.field
27
- end
28
-
29
- def unique_key
30
- @unique_key ||= get('/schema/uniquekey').uniqueKey
31
- end
32
-
33
- def field_types(**params)
34
- response = get('/schema/fieldtypes', **params)
35
- response.fieldTypes
36
- end
37
-
38
- def field_type(field_name, **params)
39
- response = get('/schema/fieldtypes/%s' % field_name, **params)
40
- response.fieldType
41
- end
42
-
43
- def field_names
44
- fields.map(&:name)
45
- end
46
-
47
- def field_type_names
48
- field_types.map(&:name)
49
- end
50
-
51
- def add_field(field)
52
- post('/schema', {"add-field"=>field})
53
- end
54
-
55
- def delete_field(field)
56
- post('/schema', {"delete-field"=>{"name"=>field.name}})
57
- end
58
-
59
- def replace_field(field)
60
- post('/schema', {"replace-field"=>field})
61
- end
62
-
63
- # "real-time get"
64
- # Note: Using POST here for simpler params.
65
- def get_by_id(*ids)
66
- response = post('/get', params: { id: ids })
67
- response.doc || response.docs
68
- end
69
-
70
- def index(*docs, **params)
71
- post('/update/json/docs', docs, **params)
72
- end
73
- alias_method :add, :index
74
- alias_method :update, :index
75
-
76
- def delete(*ids)
77
- post('/update', delete: ids)
78
- end
79
-
80
- def query(params)
81
- post('/query', Query.new(params))
82
- end
83
-
84
- end
85
- end
@@ -1,59 +0,0 @@
1
- require "net/http"
2
- require "uri"
3
- require "json"
4
-
5
- require "solrbee/api_methods"
6
-
7
- module Solrbee
8
- class Client
9
- include ApiMethods
10
-
11
- attr_reader :collection, :uri
12
-
13
- def initialize(collection)
14
- @collection = collection
15
- @uri = URI(Solrbee.solr_url).tap do |u|
16
- u.path += '/%s' % URI.encode_www_form_component(collection)
17
- end
18
- end
19
-
20
- def connection
21
- Net::HTTP.new(uri.host, uri.port).tap do |http|
22
- http.use_ssl = true if uri.scheme == 'https'
23
- end
24
- end
25
-
26
- # :get -> Net::HTTP::Get
27
- def request_class(method)
28
- Net::HTTP.const_get(method.to_s.downcase.capitalize)
29
- end
30
-
31
- def request(method, path, **params)
32
- req_uri = uri.dup
33
- req_uri.path += path
34
- unless params.empty?
35
- req_uri.query = URI.encode_www_form RequestParams.new(params)
36
- end
37
- req = request_class(method).new(req_uri, {'Accept'=>'application/json'})
38
- yield req if block_given?
39
- res = connection.request(req)
40
- Response.new JSON.parse(res.body)
41
- end
42
-
43
- def get(path, **params)
44
- request(:get, path, **params)
45
- end
46
-
47
- def post(path, data, **params)
48
- request(:post, path, **params) do |req|
49
- req['Content-Type'] = 'application/json'
50
- req.body = JSON.dump(data)
51
- end
52
- end
53
-
54
- def cursor
55
- Cursor.new(self)
56
- end
57
-
58
- end
59
- end
@@ -1,37 +0,0 @@
1
- module Solrbee
2
- #
3
- # Summary
4
- #
5
- # > client = Solrbee::Client.new('mycollection'))
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.num_found == 0
29
- break if response.nextCursorMark == q.params.cursorMark
30
- response.docs.each { |doc| yielder << doc }
31
- q.params.cursorMark = response.nextCursorMark
32
- end
33
- end
34
- end
35
-
36
- end
37
- end
@@ -1,36 +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
-
9
- property :query, from: :q, default: '*:*'
10
- property :filter, from: :fq
11
- property :limit, from: :rows, default: 10
12
- property :fields, from: :fl
13
- property :sort
14
- property :offset, from: :start
15
- property :facet
16
- property :queries
17
- property :params, default: {}
18
-
19
- # Build a query for a Cursor
20
- def self.cursor(params, unique_key)
21
- Query.new(params).tap do |q|
22
- q.delete(:offset) # incompatible with cursor
23
- q.params[:cursorMark] = '*' # initial cursor mark
24
-
25
- # Sort on unique key is required for cursor
26
- q.sort = "#{unique_key} ASC" unless q.sort
27
- unless q.sort =~ /\b#{unique_key}\b/
28
- clauses = q.sort.split(/,/)
29
- clauses << "#{unique_key} ASC"
30
- q.sort = clauses.join(',')
31
- end
32
- end
33
- end
34
-
35
- end
36
- end
@@ -1,13 +0,0 @@
1
- require 'hashie'
2
-
3
- module Solrbee
4
- #
5
- # For marshalling various API request query parameters
6
- #
7
- class RequestParams < Hashie::Trash
8
- property :showDefaults, from: :show_defaults
9
- property :includeDynamic, from: :include_dynamic
10
- property :fl
11
- property :commit
12
- end
13
- end
@@ -1,25 +0,0 @@
1
- require 'hashie'
2
-
3
- module Solrbee
4
- class Response < Hashie::Mash
5
-
6
- disable_warnings
7
-
8
- def header
9
- responseHeader
10
- end
11
-
12
- def num_found
13
- response.numFound
14
- end
15
-
16
- def docs
17
- response.docs
18
- end
19
-
20
- def doc
21
- response.doc
22
- end
23
-
24
- end
25
- end