solrbee 0.1.0 → 0.1.1

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: ca8f6d8f901268390057453075d0c39306b2362cb1216ec4dbcdb168b6d5bb18
4
- data.tar.gz: b17d0b604e4276a47c2e54d17fc92f9b9cc173fb1c2b283cc4d15f6f506c99d8
3
+ metadata.gz: 77127390eb03bfbd53eec6916f7873fab49b6436f4acb94c528f2cec7ed5f76b
4
+ data.tar.gz: '08ab2300881e0fdacaafa0007d1a17031a2b11bebfe2ade9cbf533a02a7b2b42'
5
5
  SHA512:
6
- metadata.gz: 3967982e1454c5659be6716eaf2e3a1a215046b6c3bfbe383c09810b519391017ddb4febedc861235d97b44253fd4950ad75f88dbcddc5378e33d5e37d822c59
7
- data.tar.gz: 9cd90db400ec1a2ec23daa227e6e22afb23da39328fb66384bd2cf18c52a01ee4c5db1f2620079a4a63d19096edc706de5320be3e93e67f8da5c2fb600948c61
6
+ metadata.gz: 5642a45f1013a4ddf33f4a339f0990ec218d7c3ebce3e6b3e1a0811c81256a6c155df333d7894618de9cb4a8b9e7c9eac5f178237474e96cd2de5ec7193cee83
7
+ data.tar.gz: bba5257728a581433cf72dbd4dce18ab5f8f7baea95afca7dca75c16f5fc17b509110c9e8ecb9a87713960f3eccf951d0bf11a0afe8b4ba01de2f331fcefd095
data/Makefile CHANGED
@@ -2,6 +2,13 @@ SHELL = /bin/bash
2
2
 
3
3
  .PHONY : test
4
4
  test:
5
- docker run --rm -d --name solrbee-test solr:8 solr-precreate solrbee
6
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:
7
14
  docker stop solrbee-test
data/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # Solrbee
2
2
 
3
+ ![Bee photo (c) David Chandek-Stark](https://raw.githubusercontent.com/dchandekstark/images/main/solrbee.jpg)
4
+
3
5
  Solrbee is intended as a lightweight library for interacting with a modern Solr instance
4
- using a managed schema. Our intestest is primarily in using Solr as data store, for example,
5
- as an alterative to an RDBMS.
6
+ as NoSQL data store.
7
+
8
+ We are currently building on the JSON APIs (V1).
6
9
 
7
10
  ## Installation
8
11
 
@@ -1,14 +1,12 @@
1
- require "net/http"
2
- require "uri"
3
- require "json"
4
-
5
1
  require "solrbee/version"
6
- require "solrbee/base"
7
2
  require "solrbee/response"
8
- require "solrbee/collection"
9
- require "solrbee/schema_api"
3
+ require "solrbee/request_params"
4
+ require "solrbee/query"
5
+ require "solrbee/client"
6
+ require "solrbee/cursor"
10
7
 
11
8
  module Solrbee
9
+
12
10
  class Error < StandardError; end
13
11
 
14
12
  # Single-valued field types
@@ -25,41 +23,9 @@ module Solrbee
25
23
  MDATE = "pdates"
26
24
  MBOOLEAN = "booleans"
27
25
 
26
+ # Base URL
28
27
  def self.solr_url
29
- ENV.fetch('SOLR_URL', 'http://localhost:8983/solr/')
30
- end
31
-
32
- def self.solr_uri
33
- URI(solr_url)
34
- end
35
-
36
- def self.connection
37
- Net::HTTP.new(solr_uri.host, solr_uri.port).tap do |http|
38
- http.use_ssl = true if solr_uri.scheme == 'https'
39
- end
40
- end
41
-
42
- def self.request_class(method)
43
- Net::HTTP.const_get(method.to_s.downcase.capitalize)
44
- end
45
-
46
- def self.request(method, path)
47
- u = URI.join(solr_url, path)
48
- req = request_class(method).new(u, {'Accept'=>'application/json'})
49
- yield req if block_given?
50
- res = connection.request(req)
51
- Response.handle(res)
52
- end
53
-
54
- def self.get(path)
55
- request(:get, path)
56
- end
57
-
58
- def self.post(path, data)
59
- request(:post, path) do |req|
60
- req['Content-Type'] = 'application/json'
61
- req.body = JSON.dump(data)
62
- end
28
+ ENV.fetch('SOLR_URL', 'http://localhost:8983/solr').sub(/\/\z/, '')
63
29
  end
64
30
 
65
31
  end
@@ -0,0 +1,85 @@
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
@@ -0,0 +1,59 @@
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
@@ -0,0 +1,37 @@
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
@@ -0,0 +1,36 @@
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
@@ -0,0 +1,13 @@
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,21 +1,24 @@
1
+ require 'hashie'
2
+
1
3
  module Solrbee
2
- class Response < Base
4
+ class Response < Hashie::Mash
5
+
6
+ disable_warnings
3
7
 
4
- coerce_key :schema, Schema
5
- coerce_key :fields, Array[Field]
6
- coerce_key :field, Field
7
- coerce_key :responseHeader, Header
8
- coerce_key :fieldTypes, Array[FieldType]
9
- coerce_key :fieldType, FieldType
8
+ def header
9
+ responseHeader
10
+ end
11
+
12
+ def num_found
13
+ response.numFound
14
+ end
10
15
 
11
- def self.handle(http_response)
12
- http_response.value # raises Net::HTTPServerException
13
- parsed = JSON.parse(http_response.body, symbolize_names: true, object_class: Solrbee::Base)
14
- new(parsed)
16
+ def docs
17
+ response.docs
15
18
  end
16
19
 
17
- def status
18
- responseHeader.status
20
+ def doc
21
+ response.doc
19
22
  end
20
23
 
21
24
  end
@@ -1,3 +1,3 @@
1
1
  module Solrbee
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
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.1.0
4
+ version: 0.1.1
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-02 00:00:00.000000000 Z
11
+ date: 2020-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -97,10 +97,12 @@ files:
97
97
  - bin/console
98
98
  - bin/setup
99
99
  - lib/solrbee.rb
100
- - lib/solrbee/base.rb
101
- - lib/solrbee/collection.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
102
105
  - lib/solrbee/response.rb
103
- - lib/solrbee/schema_api.rb
104
106
  - lib/solrbee/version.rb
105
107
  - solrbee.gemspec
106
108
  homepage: https://github.com/dchandekstark/solrbee
@@ -1,14 +0,0 @@
1
- require 'hashie'
2
-
3
- module Solrbee
4
- class Base < Hashie::Hash
5
- include Hashie::Extensions::Coercion
6
- include Hashie::Extensions::MergeInitializer
7
- include Hashie::Extensions::MethodAccess
8
- end
9
-
10
- Field = Class.new(Base)
11
- FieldType = Class.new(Base)
12
- Header = Class.new(Base)
13
- Schema = Class.new(Base)
14
- end
@@ -1,19 +0,0 @@
1
- module Solrbee
2
- class Collection
3
-
4
- attr_reader :name
5
-
6
- def initialize(name)
7
- @name = name
8
- end
9
-
10
- def to_s
11
- name
12
- end
13
-
14
- def schema
15
- @schema ||= SchemaApi.new(self)
16
- end
17
-
18
- end
19
- end
@@ -1,86 +0,0 @@
1
- module Solrbee
2
- class SchemaApi
3
-
4
- attr_reader :collection
5
-
6
- def initialize(collection)
7
- @collection = collection
8
- end
9
-
10
- def to_h
11
- content
12
- end
13
-
14
- def name
15
- response = Solrbee.get('%s/schema/name' % collection)
16
- response.name
17
- end
18
-
19
- def version
20
- response = Solrbee.get('%s/schema/version' % collection)
21
- response.version
22
- end
23
-
24
- def content
25
- response = Solrbee.get('%s/schema' % collection)
26
- response.schema
27
- end
28
-
29
- def fields(show_defaults: true)
30
- response = Solrbee.get('%s/schema/fields?showDefaults=%s' % [collection, show_defaults])
31
- response.fields
32
- end
33
-
34
- def field(field_name, show_defaults: true)
35
- response = Solrbee.get('%s/schema/fields/%s?showDefaults=%s' % [collection, field_name, show_defaults])
36
- response.field
37
- end
38
-
39
- def unique_key
40
- response = Solrbee.get('%s/schema/uniquekey' % collection)
41
- response.uniqueKey
42
- end
43
-
44
- def field_types(show_defaults: true)
45
- response = Solrbee.get('%s/schema/fieldtypes?showDefaults=%s' % [collection, show_defaults])
46
- response.fieldTypes
47
- end
48
-
49
- def field_type(field_name, show_defaults: true)
50
- response = Solrbee.get('%s/schema/fieldtypes/%s?showDefaults=%s' % [collection, field_name, show_defaults])
51
- response.fieldType
52
- end
53
-
54
- def field_names
55
- fields.map(&:name)
56
- end
57
-
58
- def field_type_names
59
- field_types.map(&:name)
60
- end
61
-
62
- def index(*docs, commit: true)
63
- Solrbee.post('%s/update/json/docs?commit=%s' % [collection, commit], docs)
64
- end
65
-
66
- def add_field(field)
67
- data = { "add-field" => field }
68
- Solrbee.post('%s/schema' % collection, data)
69
- end
70
-
71
- def delete_field(field)
72
- data = {
73
- "delete-field" => {
74
- "name" => field.name
75
- }
76
- }
77
- Solrbee.post('%s/schema' % collection, data)
78
- end
79
-
80
- def replace_field(field)
81
- data = { "replace-field" => field }
82
- Solrbee.post('%s/schema' % collection, data)
83
- end
84
-
85
- end
86
- end