solr_cloud-connection 0.4.0 → 0.6.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: 2257fc2ce8c0a649712a66c5154222cfd6d2e0b0d837df583d297eba3d19d6bb
4
- data.tar.gz: b9fdf5d5dd5a3c8d2fe4ec5a0e47f414fc9186a020292d34631e887591528327
3
+ metadata.gz: da67e9a6312ae058259368a9933abe711d1c0554337c59c5f688cf2f17cee606
4
+ data.tar.gz: 36b815217b2f3e806d9b639d4839f093d61327ee496fee1c3d4774039c688e48
5
5
  SHA512:
6
- metadata.gz: 53b06b39cb208dff15696c94541aae3e3069d577be2b16d587f3a8fb86594dac0eef88a9fc4800564d469bfe898ae281421b04fef957af89472085e420f60de2
7
- data.tar.gz: 3a6daabf59f8dc61fdd2d21019596714649219e50ce6983a4c6ba873d188782c6b3b6a32e932d66512e3e9eab83f4516137f3605f22fbab968811e73e5d78170
6
+ metadata.gz: c828e6c7f7976cee46ac7b81c8955d2253253e3084e3841e26a502bf2d03808327578e69e63a47c0907dd7d38df3db27747a2383a6e8a6f9f4b1a73c69832340
7
+ data.tar.gz: 25548a6825b308a62ec376bf1b59d596a557c8508f9feeb56cabd5bc402907ecf4f7602658c5087483424844d1fffddf2c7673ecc2f16cefb3ad79f03696aba5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0] - 2025-03-24
4
+ - Added some sugar for unifying aliases and collections
5
+ - Update tests
6
+ - Better errors
7
+ - Flesh out README.md to be a useful document
8
+
9
+
3
10
  ## [0.4.0] - 2023-12-07
4
11
  - Fixed rules about what names are legal collections/configsets/aliases
5
12
  - Update version and changelog
data/README.md CHANGED
@@ -1,14 +1,36 @@
1
1
  # SolrCloud::Connection
2
2
 
3
- Do basic administrative tasks on a running Solr cloud instance, including:
3
+ ## Common usage
4
4
 
5
- * create (i.e., upload) a configSet when given a `conf` directory
6
- * list, create, and delete configsets, collections, and aliases
7
- * get basic version information for the running solr
8
- * check on the health of individual collections
9
- * treat an alias (mostly) as a collection
10
- * TODO automatically generate methods to talk to defined requestHandlers
11
- * TODO Add something useful for configsets to do
5
+ ```ruby
6
+
7
+ # Connect to the server, upload a config set, make a collection based on it,
8
+ # and make an alias pointing to that collection
9
+
10
+ server = SolrCloud::Connection.new(url: url, user: user, password: pass)
11
+ cfg = server.create_configset(name: "my_cfg", confdir: "/path/to/my/conf")
12
+ cars_v1 = server.create_collection(name: "cars_v1", configset: "my_cfg")
13
+ cars = cars_v1.alias_as("cars")
14
+
15
+ ```
16
+
17
+ ## Basic functionality / Roadmap
18
+
19
+ Do basic administrative tasks on a running Solr cloud instance
20
+
21
+ * [x] create (i.e., upload) a configSet when given a `conf` directory
22
+ * [x] list, create, and delete configsets, collections, and aliases
23
+ * [x] get basic version information for the running solr
24
+ * [x] check on the health of individual collections
25
+ * [x] treat an alias (mostly) as a collection
26
+ * [ ] automatically generate methods to talk to defined requestHandlers and updateHandlers
27
+ * [ ] provide a way to talk to the analyzer for testing of fieldTypes
28
+ * [ ] hook into the schema API
29
+ * [ ] allow it to work with cores, and not just solrcloud collections (which, you know bad naming then)
30
+ * [ ] figure out how to deal with managed resources
31
+ * [ ] get info from updateHandler metrics, esp. pending documents and cumulative errors
32
+ * [ ] hook into performance metrics for easy reporting and checks
33
+ * [ ] support more of the v2 API
12
34
 
13
35
  In almost all cases, you can treat an alias to a collection like the underlying collection.
14
36
 
@@ -22,7 +44,7 @@ a collections that's pointed to by an alias.
22
44
  ## Caveats
23
45
 
24
46
  * At this point the API is unstable
25
- * Performance is desperately, hilariously terrible. Solr has no sense of an atomic action and plenty of other ways
47
+ * Solr has no sense of an atomic action and plenty of other ways
26
48
  (e.g, the admin interface) to mess with things, so nothing is cached.
27
49
  This means that individual actions can involve several round-trips to solr. If you're doing so much admin
28
50
  that this becomes a bottleneck, you're well outside this gem's target case.
@@ -34,70 +56,179 @@ a collections that's pointed to by an alias.
34
56
  The code below covers all the basics. See the docs for full sets of parameters, which errors are
35
57
  thrown, etc.
36
58
 
59
+
60
+ ### Create a connection to the server
61
+
37
62
  ```ruby
63
+ url = "http://localhost:9090/"
64
+ user = "solr"
65
+ password = "SolrRocks"
66
+ config_directory = "/path/to/myconfig/conf" # Directory 'conf' contains solrconfig.xml
38
67
 
39
68
  require "solr_cloud/connection"
40
69
 
41
- server = SolrCloud::connect.new(url: "http://localhost:8023", username: "user", password: "password")
42
- # #=> <SolrCloud::Connection http://localhost:8023/>
70
+ server = SolrCloud::Connection.new(url: url, user: user, password: pass)
71
+ #=> <SolrCloud::Connection http://localhost:9090>
43
72
 
44
- # or bring your own Faraday object
45
- # server = SolrCloud::connect.new_with_faraday(faraday_connection)
73
+ # or bring your own Faraday object
74
+ # server2 = SolrCloud::Connection.new_with_faraday(faraday_connection)
75
+
76
+ ### Get some basic info
77
+
78
+ server.version_string #=> "8.11.2"
79
+ server.cloud? #=> true
80
+ server.mode #=> "solrcloud"
81
+ ```
46
82
 
83
+ ### Configsets
84
+ ```ruby
85
+ # List the configsets
86
+ server.configsets #=> [<SolrCloud::Configset '_default' at http://localhost:9090>]
87
+
88
+ # Sometimes you just want the names.
47
89
  server.configset_names #=> ["_default"]
48
- default = server.get_configset("_default") #=> <SolrCloud::Configset '_default' at http://localhost:8983>
49
90
 
50
- # Create a new one by taking a directory, zipping it up, and sending it to solr
51
- cset = server.create_configset(name: "my_awesome_configset_for_cars", confdir: "/path/to/mycore/conf")
52
- server.configset_names #=> ["_default", "my_awesome_configset_for_cars"]
91
+ # Create a new configset by taking a conf directory, zipping it up,
92
+ # and sending it to solr
93
+ cset = server.create_configset(name: "horseless", confdir: config_directory)
94
+ #=> <SolrCloud::Configset 'horseless' at http://localhost:9090>
95
+ server.configset_names #=> ["_default", "horseless"]
53
96
 
54
- # That's a dumb name. We'll try again.
55
- cset.delete!
56
- cset = server.create_configset(name: "cars_config", confdir: "/path/to/mycore/conf")
97
+ # That's a dumb name for a config set. Delete it and try again.
98
+ cset.delete! #=> <SolrCloud::Connection http://localhost:9090>
99
+ cset = server.create_configset(name: "cars_cfg", confdir: config_directory)
100
+ #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
101
+ server.configsets
102
+ #=> [<SolrCloud::Configset '_default' at http://localhost:9090>,
103
+ # <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>]
57
104
 
58
- # Collections and aliases are mostly treated the same
59
- server.collection_names #=> ["cars_v1", "cars_v2", "cars"] -- collections AND aliases
60
- server.only_collection_names #=> ["cars_v1", "cars_v2"]
61
- server.alias_names #=> ["cars"]
105
+ # Can't be overwritten by accident
106
+ server.create_configset(name: "cars_cfg", confdir: config_directory)
107
+ #=> raised #<SolrCloud::WontOverwriteError: Won't replace configset cars_cfg unless 'force: true' passed >
62
108
 
63
- typo = server.get_collection("cars__V2") #=> nil, doesn't exist
64
- cars_v2 = server.get_collection("cars_v2")
109
+ # But you can force it
110
+ server.create_configset(name: "cars_cfg", confdir: config_directory, force: true)
111
+ #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
65
112
 
66
- cars_v2.alive? #=> true
67
- cars_v2.count #=> 133 -- we're assuming there's stuff in it.
113
+ cfg = server.get_configset("cars_cfg") #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
114
+ cfg.in_use? #=> false
68
115
 
116
+ ```
69
117
 
70
- # Find out about its aliases, if any
71
- cars_v2.alias? #=> false. It's a true collection
72
- cars_v2.aliased? #=> true
73
- cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")> ]
74
- cars_v2.has_alias?("cars") #=> true
118
+ ### Collections
75
119
 
76
- cars_v2.delete! #=> SolrCloud::CollectionAliasedError: Collection 'cars_v2' can't be deleted; it's in use by aliases ["cars"]
120
+ ```ruby
121
+ # Now create a collection based on an already-existing configset
122
+ cars_v1 = server.create_collection(name: "cars_v1", configset: "cars_cfg")
123
+ #=> <SolrCloud::Collection 'cars_v1'>
124
+ server.collections #=> [<SolrCloud::Collection 'cars_v1'>]
125
+ server.collection_names #=> ["cars_v1"]
77
126
 
78
- # Make a new collection
79
- cars_v3 = server.create_collection(name: "cars_v3", configset: "cars_config")
80
- cars_v3.aliased? #=> false
81
- cars_v3.count #=> 0
82
- cars_v3.configset #=> <SolrCloud::Configset 'cars_config' at http://localhost:8023>
127
+ # Check it out quick
128
+ cars_v1.alive? #=> "OK"
129
+ cars_v1.healthy? #=> true
130
+ cars_v1.count #=> 0
83
131
 
84
- # Work directly with an alias as if it's a collection
85
- cars = server.get_collection("cars")
86
- cars.alias? #=> true
132
+ # Any aliases
133
+ cars_v1.aliased? #=> false
134
+ cars_v1.aliases #=> []
135
+
136
+ # Its configset
137
+ cars_v1.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
138
+
139
+ # Commit anything that's been added
140
+ cars_v1.commit #=> <SolrCloud::Collection 'cars_v1'>
141
+
142
+ # Solr knows when a configset is in use, and won't delete it
143
+
144
+ cfg.delete!
145
+ #=> raised #<SolrCloud::ConfigSetInUseError: Can not delete ConfigSet
146
+ # as it is currently being used by collection [cars_v1]>
147
+
148
+ ```
149
+
150
+ ### Aliases
151
+
152
+ ```ruby
153
+ # We'll want to alias it so we can just use 'cars'
154
+ cars = cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
155
+ cars_v1.alias? #=> false
156
+ cars_v1.aliased? #=> true
157
+
158
+ cars_v1.has_alias?("cars") #=> true
159
+ cars_v1.alias_as("autos") #=> <SolrCloud::Alias 'autos' (alias of 'cars_v1')>
160
+ cars_v1.aliases
161
+ #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>, <SolrCloud::Alias 'autos' (alias of 'cars_v1')>]
162
+
163
+ cars_v1.get_alias("autos").delete! #=> <SolrCloud::Connection http://localhost:9090>
164
+ cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]
165
+
166
+ # There's syntactic sugar for switching out aliases
167
+ cars_v2 = server.create_collection(name: "cars_v2", configset: "cars_cfg") #=> <SolrCloud::Collection 'cars_v2'>
168
+ cars = server.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
169
+
170
+ cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
171
+ cars.switch_collection_to("cars_v2") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v2')>
87
172
  cars.collection #=> <SolrCloud::Collection 'cars_v2' (aliased by 'cars')>
173
+ cars_v1.aliases #=> []
174
+ cars_v2.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v2')>]
175
+
176
+ # Aliases will swap from collection to collection without warning
177
+ cars_v1.alias_as("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
178
+
179
+ # ...unless you use the bang(!) version
180
+ cars_v2.alias_as!("cars") #=> raised #<SolrCloud::AliasAlreadyDefinedError: Alias cars already points to cars_v1>
181
+
182
+ # You can also just switch it from the alias itself.
183
+ cars.switch_collection_to("cars_v1") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
184
+
185
+ # Aliases show up as "collections" so you can just use them interchangeably
186
+ server.collection_names #=> ["cars_v1", "cars_v2", "cars"]
187
+
188
+ # They even == to each other
189
+ cars #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
190
+ cars == cars_v1 #=> true
191
+ cars == cars_v2 #=> false
192
+
193
+ # But sometimes you want to differentiate them from each other
194
+ server.only_collection_names #=> ["cars_v1", "cars_v2"]
195
+ cars.alias? #=> true
196
+ cars_v1.alias? #=> false
197
+
198
+ cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
199
+
200
+ ```
201
+
202
+ ### Accessing objects from other objects
203
+
204
+ ```ruby
205
+ # You can grab existing collections/aliases/configsets from the server
206
+ # as well as when they're returned by a create_* statement
207
+ cv1 = server.get_collection("cars_v1") #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
208
+ cars = server.get_collection("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
209
+
210
+ # get_* methods might return nil
211
+ typo = "cars_V1" #=> "cars_V1"
212
+ server.has_collection?(typo) #=> false
213
+ dne = server.get_collection(typo) #=> nil
214
+
215
+ # get_*! methods will throw an error
216
+ dne = server.get_collection!(typo) #=> raised #<SolrCloud::NoSuchCollectionError: Collection 'cars_V1' not found>
217
+
218
+ # alias#collection returns the underlying collection.
219
+ # collection#collection returns itself. This makes it easier to
220
+ # write code without differentiating between them.
88
221
 
89
- # Make a new alias to v2
90
- old_cars = cars_v2.alias_as("old_cars") #=> <SolrCloud::Alias "old_cars" (alias of "cars_v2")>
91
- cars_v2.aliases #=> [<SolrCloud::Alias "cars" (alias of "cars_v2")>, <SolrCloud::Alias "old_cars" (alias of "cars_v2")>]
222
+ cars.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
223
+ cars_v1.collection #=> <SolrCloud::Collection 'cars_v1' (aliased by 'cars')>
92
224
 
93
- # Now lets point the "cars" alias at cars_v3
94
- cars.switch_collection_to cars_v3
225
+ # Configsets, Aliases, and Collections know how they're related
95
226
 
96
- cars.collection.name #=> "cars_v3"
97
- cars_v2.alias_names #=> ["old_cars"]
227
+ cars_v1.aliases #=> [<SolrCloud::Alias 'cars' (alias of 'cars_v1')>]
228
+ cars = cars_v1.get_alias("cars") #=> <SolrCloud::Alias 'cars' (alias of 'cars_v1')>
229
+ cfg = cars.configset #=> <SolrCloud::Configset 'cars_cfg' at http://localhost:9090>
230
+ cfg.collections #=> [<SolrCloud::Collection 'cars_v1' (aliased by 'cars')>, <SolrCloud::Collection 'cars_v2'>]
98
231
 
99
- # cars_v1 isn't doing anything for us anymore. Ditch it.
100
- cars_v1.delete!
101
232
 
102
233
  ```
103
234
 
@@ -126,4 +257,5 @@ This repository is set up to run tests under docker.
126
257
 
127
258
  ## Contributing
128
259
 
129
- Bug reports and pull requests are welcome on GitHub at https://github.com/mlibrary/solr_cloud-connection.
260
+ Bugs, functionality suggestions, API suggestions, feature requests, etc. all welcome
261
+ on GitHub at https://github.com/mlibrary/solr_cloud-connection.
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ require "standard/rake"
10
10
  task default: %i[spec standard docs]
11
11
  task docs: %i[yard]
12
12
 
13
- require 'yard'
13
+ require "yard"
14
14
 
15
15
  YARD::Rake::YardocTask.new do |t|
16
16
  t.files = ["lib/**/*.rb"] # optional
@@ -41,13 +41,13 @@ module SolrCloud
41
41
  # @return [Collection] the now-current collection
42
42
  def switch_collection_to(coll)
43
43
  collect_name = case coll
44
- when String
45
- coll
46
- when Collection
47
- coll.name
48
- else
49
- raise "Alias#switch_collection_to only takes a name(string) or a collection, not '#{coll}'"
50
- end
44
+ when String
45
+ coll
46
+ when Collection
47
+ coll.name
48
+ else
49
+ raise "Alias#switch_collection_to only takes a name(string) or a collection, not '#{coll}'"
50
+ end
51
51
  raise NoSuchCollectionError unless connection.has_collection?(collect_name)
52
52
  connection.create_alias(name: name, collection_name: collect_name, force: true)
53
53
  end
@@ -7,7 +7,6 @@ module SolrCloud
7
7
  # A Collection provides basic services on the collection -- checking its health,
8
8
  # creating or reporting aliases, and deleting itself.
9
9
  class Collection
10
-
11
10
  extend Forwardable
12
11
 
13
12
  # Forward the HTTP verbs to the underlying connection
@@ -50,13 +49,26 @@ module SolrCloud
50
49
  @sp = "/solr/#{name}"
51
50
  end
52
51
 
52
+ def collection
53
+ self
54
+ end
55
+
56
+ def ==(other)
57
+ case other
58
+ when SolrCloud::Collection
59
+ collection.name == other.collection.name
60
+ else
61
+ false
62
+ end
63
+ end
64
+
53
65
  # Delete this collection. Will no-op if the collection somehow doesn't still exist (because it was
54
66
  # deleted via a different method, such as through the API)
55
67
  # @return [Connection] The connection object used to create this collection object
56
68
  def delete!
57
69
  return connection unless exist?
58
70
  raise CollectionAliasedError.new("Cannot delete collection #{name}; it has alias(s) #{alias_names.join(", ")}") if aliased?
59
- connection.get("solr/admin/collections", { action: "DELETE", name: name })
71
+ connection.get("solr/admin/collections", {action: "DELETE", name: name})
60
72
  connection
61
73
  end
62
74
 
@@ -74,6 +86,8 @@ module SolrCloud
74
86
  false
75
87
  end
76
88
 
89
+ alias_method :ping, :alive?
90
+
77
91
  # Is this an alias?
78
92
  # Putting this in here breaks all sorts of isolation principles,
79
93
  # but being able to call #get_alias? on anything collection-like is
@@ -136,6 +150,13 @@ module SolrCloud
136
150
  connection.create_alias(name: alias_name, collection_name: name, force: true)
137
151
  end
138
152
 
153
+ def alias_as!(alias_name)
154
+ if connection.has_alias?(alias_name)
155
+ raise AliasAlreadyDefinedError.new("Alias #{alias_name} already points to #{connection.get_alias(alias_name).collection.name}")
156
+ end
157
+ alias_as(alias_name, force: false)
158
+ end
159
+
139
160
  # Send a commit (soft if unspecified)
140
161
  # @return self
141
162
  def commit(hard: false)
@@ -160,10 +181,10 @@ module SolrCloud
160
181
 
161
182
  def add(docs)
162
183
  docarray = if docs === Array
163
- docs
164
- else
165
- [docs]
166
- end
184
+ docs
185
+ else
186
+ [docs]
187
+ end
167
188
  post("solr/#{name}/update/") do |r|
168
189
  r.body = docarray
169
190
  end
@@ -179,10 +200,10 @@ module SolrCloud
179
200
  def inspect
180
201
  anames = alias_names
181
202
  astring = if anames.empty?
182
- ""
183
- else
184
- " (aliased by #{anames.map { |x| "'#{x}'" }.join(", ")})"
185
- end
203
+ ""
204
+ else
205
+ " (aliased by #{anames.map { |x| "'#{x}'" }.join(", ")})"
206
+ end
186
207
  "<#{self.class} '#{name}'#{astring}>"
187
208
  end
188
209
 
@@ -7,7 +7,6 @@ module SolrCloud
7
7
  # throw an error if that's an illegal operation (because a collection is
8
8
  # using it)
9
9
  class Configset
10
-
11
10
  # @return [String] the name of this configset
12
11
  attr_reader :name
13
12
 
@@ -33,6 +32,8 @@ module SolrCloud
33
32
  connection.only_collections.select { |coll| coll.configset.name == name }
34
33
  end
35
34
 
35
+ alias_method :collections, :used_by
36
+
36
37
  # Are there any collections currently using this configset?
37
38
  # @return [Boolean]
38
39
  def in_use?
@@ -5,7 +5,6 @@ module SolrCloud
5
5
  # methods having to do with aliases, to be included by the connection object.
6
6
  # These are split out only to make it easier to deal with them.
7
7
  module AliasAdmin
8
-
9
8
  # A simple data-class to pair an alias with its collection
10
9
  AliasCollectionPair = Struct.new(:alias, :collection)
11
10
 
@@ -24,7 +23,7 @@ module SolrCloud
24
23
  end
25
24
  raise NoSuchCollectionError.new("Can't find collection #{collection_name}") unless has_collection?(collection_name)
26
25
  if has_alias?(name) && !force
27
- raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{self.get_alias(name).collection.name}'; won't overwrite without force: true")
26
+ raise WontOverwriteError.new("Alias '#{name}' already points to collection '#{get_alias(name).collection.name}'; won't overwrite without force: true")
28
27
  end
29
28
  connection.get("solr/admin/collections", action: "CREATEALIAS", name: name, collections: collection_name)
30
29
  get_alias(name)
@@ -83,5 +82,3 @@ module SolrCloud
83
82
  end
84
83
  end
85
84
  end
86
-
87
-
@@ -20,17 +20,16 @@ module SolrCloud
20
20
  # @raise [WontOverwriteError] if the collection already exists
21
21
  # @return [Collection] the collection created
22
22
  def create_collection(name:, configset:, shards: 1, replication_factor: 1)
23
-
24
23
  unless legal_solr_name?(name)
25
24
  raise IllegalNameError.new("'#{name}' is not a valid solr name. Use only ASCII letters/numbers, dash, and underscore")
26
25
  end
27
26
 
28
27
  configset_name = case configset
29
- when Configset
30
- configset.name
31
- else
32
- configset.to_s
33
- end
28
+ when Configset
29
+ configset.name
30
+ else
31
+ configset.to_s
32
+ end
34
33
  raise WontOverwriteError.new("Collection #{name} already exists") if has_collection?(name)
35
34
  raise NoSuchConfigSetError.new("Configset '#{configset_name}' doesn't exist") unless has_configset?(configset_name)
36
35
 
@@ -7,7 +7,6 @@ module SolrCloud
7
7
  # methods having to do with configsets, to be included by the connection object.
8
8
  # These are split out only to make it easier to deal with them.
9
9
  module ConfigsetAdmin
10
-
11
10
  # Given the path to a solr configuration "conf" directory (i.e., the one with
12
11
  # solrconfig.xml in it), zip it up and send it to solr as a new configset.
13
12
  # @param name [String] Name to give the new configset
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SolrCloud
4
4
  class Connection
5
- VERSION = "0.4.0"
5
+ VERSION = "0.6.0"
6
6
  end
7
7
  end
@@ -31,12 +31,20 @@ module SolrCloud
31
31
  # @return [String] String representation of the URL to solr
32
32
  attr_reader :url
33
33
 
34
+ # @return [String] solr user
35
+ attr_reader :user
36
+ alias_method :username, :user
37
+
38
+ # @return [String] Solr password
39
+ attr_reader :password
40
+
34
41
  # @return [#info] The logger
35
42
  attr_reader :logger
36
43
 
37
44
  # @return [Faraday::Connection] the underlying Faraday connection
38
45
  attr_reader :connection
39
46
 
47
+
40
48
  # let the underlying connection handle HTTP verbs
41
49
 
42
50
  # @!method get
@@ -72,12 +80,12 @@ module SolrCloud
72
80
  @user = user
73
81
  @password = password
74
82
  @logger = case logger
75
- when :off, :none
76
- Logger.new(File::NULL, level: Logger::FATAL)
77
- when nil
78
- Logger.new($stderr, level: Logger::WARN)
79
- else
80
- logger
83
+ when :off, :none
84
+ Logger.new(File::NULL, level: Logger::FATAL)
85
+ when nil
86
+ Logger.new($stderr, level: Logger::WARN)
87
+ else
88
+ logger
81
89
  end
82
90
  @connection = create_raw_connection(url: url, adapter: adapter, user: user, password: password, logger: @logger)
83
91
  bail_if_incompatible!
@@ -112,10 +120,6 @@ module SolrCloud
112
120
  end
113
121
  end
114
122
 
115
- # Allow accessing the raw_connection via "connection". Yes, connection.connection
116
- # can be confusing, but it makes the *_admin stuff easier to read.
117
- alias_method :connection, :connection
118
-
119
123
  # Check to see if we can actually talk to the solr in question
120
124
  # raise [UnsupportedSolr] if the solr version isn't at least 8
121
125
  # raise [ConnectionFailed] if we can't connect for some reason
@@ -192,6 +196,3 @@ module SolrCloud
192
196
  end
193
197
  end
194
198
  end
195
-
196
-
197
-
@@ -10,6 +10,8 @@ module SolrCloud
10
10
 
11
11
  class WontOverwriteError < RuntimeError; end
12
12
 
13
+ class AliasAlreadyDefinedError < RuntimeError; end
14
+
13
15
  class ConfigSetInUseError < RuntimeError; end
14
16
 
15
17
  class CollectionAliasedError < RuntimeError; end
data/readme.rb ADDED
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ $LOAD_PATH.unshift Pathname.new(__dir__) + "lib"
5
+ require_relative "lib/solr_cloud/connection"
6
+ config_directory = "/Users/dueberb/devel/mlibrary/solr_cloud-connection/spec/data/simple_configuration/conf"
7
+ url = "http://localhost:9090"
8
+ user = "solr"
9
+ pass = "SolrRocks"
10
+
11
+ server = SolrCloud::Connection.new(url: url, user: user, password: pass) #=>
12
+
13
+ server.aliases.each { |a| a.delete! }
14
+ server.collections.each { |c| c.delete! }
15
+ server.configsets.reject { |c| c.name == "_default" }.each { |c| c.delete! }
16
+
17
+ # or bring your own Faraday object
18
+ # server2 = SolrCloud::Connection.new_with_faraday(faraday_connection)
19
+
20
+ ### Get some basic info
21
+
22
+ server.version_string
23
+ server.cloud?
24
+ server.mode
25
+
26
+ ### Configsets
27
+
28
+ # List the configsets
29
+ server.configsets
30
+
31
+ # Sometimes you just want the names.
32
+ server.configset_names
33
+
34
+ # Create a new configset by taking a conf directory, zipping it up,
35
+ # and sending it to solr
36
+ cset = server.create_configset(name: "horseless", confdir: config_directory)
37
+ server.configset_names
38
+
39
+ # That's a dumb name for a config set. Delete it and try again.
40
+ cset.delete!
41
+ cset = server.create_configset(name: "cars_cfg", confdir: config_directory)
42
+ server.configsets
43
+
44
+ # Can't be overwritten by accident
45
+ begin
46
+ server.create_configset(name: "cars_cfg", confdir: config_directory)
47
+ rescue => e
48
+ end
49
+
50
+ # But you can force it
51
+ server.create_configset(name: "cars_cfg", confdir: config_directory, force: true)
52
+
53
+ cfg = server.get_configset("cars_cfg")
54
+ cfg.in_use?
55
+
56
+ #### Collections
57
+
58
+ # Now create a collection based on an already-existing configset
59
+ cars_v1 = server.create_collection(name: "cars_v1", configset: "cars_cfg")
60
+ server.collections
61
+ server.collection_names
62
+
63
+ # Check it out quick
64
+ cars_v1.alive?
65
+ cars_v1.healthy?
66
+ cars_v1.count
67
+
68
+ # Any aliases
69
+ cars_v1.aliased?
70
+ cars_v1.aliases
71
+
72
+ # Its configset
73
+ cars_v1.configset
74
+
75
+ # Commit anything that's been added
76
+ cars_v1.commit
77
+
78
+ # Solr knows its configset is in use, and won't delete it
79
+
80
+ begin
81
+ cfg.delete!
82
+ rescue
83
+ end
84
+
85
+ ##### Aliases
86
+
87
+ # We'll want to alias it so we can just use 'cars'
88
+ cars = cars_v1.alias_as("cars")
89
+ cars_v1.alias?
90
+ cars_v1.aliased?
91
+
92
+ cars_v1.has_alias?("cars")
93
+ cars_v1.alias_as("autos")
94
+ cars_v1.aliases
95
+
96
+ cars_v1.get_alias("autos").delete!
97
+ cars_v1.aliases
98
+
99
+ # There's syntactic sugar for switching out aliases
100
+ cars_v2 = server.create_collection(name: "cars_v2", configset: "cars_cfg")
101
+ cars = server.get_alias("cars")
102
+
103
+ cars.collection
104
+ cars.switch_collection_to("cars_v2")
105
+ cars.collection
106
+ cars_v1.aliases
107
+ cars_v2.aliases
108
+
109
+ # Aliases will swap from collection to collection without warning
110
+ cars_v1.alias_as("cars")
111
+
112
+ # ...unless you use the bang(!) version
113
+ begin
114
+ cars_v2.alias_as!("cars")
115
+ rescue
116
+ end
117
+
118
+ # You can also just switch it from the alias itself.
119
+ cars.switch_collection_to("cars_v1")
120
+
121
+ # Aliases show up as "collections" so you can just use them interchangeably
122
+ server.collection_names
123
+
124
+ # They even == to each other
125
+
126
+ # But sometimes you want to differentiate them from each other
127
+ server.only_collection_names
128
+ cars.alias?
129
+ cars_v1.alias?
130
+
131
+ cars.collection
132
+
133
+ ### Ways to get access to aliases/collections/configsets
134
+
135
+ # You can grab existing collections/aliases/configsets from the server
136
+ # as well as when they're returned by a create_* statement
137
+ cv1 = server.get_collection("cars_v1")
138
+ cars = server.get_collection("cars")
139
+
140
+ # get_*! methods raise an error
141
+ typo = "cars_V1"
142
+ server.has_collection?(typo)
143
+ dne = server.get_collection(typo)
144
+
145
+ begin
146
+ dne = server.get_collection!(typo)
147
+ rescue
148
+ end
149
+
150
+ # alias#collection returns the underlying collection.
151
+ # collection#collection returns itself. This makes it easier to
152
+ # write code without differentiating between them.
153
+
154
+ cars.collection
155
+ cars_v1.collection
156
+
157
+ # Configsets, Aliases, and Collections know how they're related
158
+
159
+ cars_v1.aliases
160
+ cars = cars_v1.get_alias("cars")
161
+ cfg = cars.configset
162
+ cfg.collections
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solr_cloud-connection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bill Dueber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-07 00:00:00.000000000 Z
11
+ date: 2024-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -16,112 +16,144 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.7.12
19
+ version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.7.12
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: httpx
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.5
33
+ version: '1.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.5
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rubyzip
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.3.0
47
+ version: '2.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.3.0
54
+ version: '2.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '13.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: dotenv
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0'
75
+ version: '3.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: '3.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: standard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 1.35.0
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '1.0'
90
93
  type: :development
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - ">="
95
98
  - !ruby/object:Gem::Version
96
- version: '0'
99
+ version: 1.35.0
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.0'
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: simplecov
99
105
  requirement: !ruby/object:Gem::Requirement
100
106
  requirements:
101
107
  - - ">="
102
108
  - !ruby/object:Gem::Version
103
- version: '0'
109
+ version: 0.22.0
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: '0.0'
104
113
  type: :development
105
114
  prerelease: false
106
115
  version_requirements: !ruby/object:Gem::Requirement
107
116
  requirements:
108
117
  - - ">="
109
118
  - !ruby/object:Gem::Version
110
- version: '0'
119
+ version: 0.22.0
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '0.0'
111
123
  - !ruby/object:Gem::Dependency
112
124
  name: yard
113
125
  requirement: !ruby/object:Gem::Requirement
114
126
  requirements:
115
127
  - - ">="
116
128
  - !ruby/object:Gem::Version
117
- version: '0'
129
+ version: 0.9.0
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: 0.9.0
118
133
  type: :development
119
134
  prerelease: false
120
135
  version_requirements: !ruby/object:Gem::Requirement
121
136
  requirements:
122
137
  - - ">="
123
138
  - !ruby/object:Gem::Version
124
- version: '0'
139
+ version: 0.9.0
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: 0.9.0
143
+ - !ruby/object:Gem::Dependency
144
+ name: dotenv
145
+ requirement: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: '3.0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '3.0'
125
157
  description:
126
158
  email:
127
159
  - bill@dueber.com
@@ -148,6 +180,7 @@ files:
148
180
  - lib/solr_cloud/connection/configset_admin.rb
149
181
  - lib/solr_cloud/connection/version.rb
150
182
  - lib/solr_cloud/errors.rb
183
+ - readme.rb
151
184
  homepage: https://github.com/mlibrary/solr_cloud-connection
152
185
  licenses: []
153
186
  metadata:
@@ -169,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
202
  - !ruby/object:Gem::Version
170
203
  version: '0'
171
204
  requirements: []
172
- rubygems_version: 3.4.17
205
+ rubygems_version: 3.5.11
173
206
  signing_key:
174
207
  specification_version: 4
175
208
  summary: Do basic administrative operations on a solr cloud instance and collections