active-fedora 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/.gitignore +1 -0
  2. data/History.txt +16 -0
  3. data/README.textile +12 -7
  4. data/active-fedora.gemspec +2 -2
  5. data/lib/active_fedora.rb +1 -0
  6. data/lib/active_fedora/associations/association_collection.rb +1 -1
  7. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +12 -3
  8. data/lib/active_fedora/associations/has_many_association.rb +4 -0
  9. data/lib/active_fedora/attributes.rb +6 -0
  10. data/lib/active_fedora/auditable.rb +9 -0
  11. data/lib/active_fedora/base.rb +2 -0
  12. data/lib/active_fedora/delegating.rb +5 -3
  13. data/lib/active_fedora/indexing.rb +1 -1
  14. data/lib/active_fedora/nokogiri_datastream.rb +1 -2
  15. data/lib/active_fedora/querying.rb +1 -0
  16. data/lib/active_fedora/version.rb +1 -1
  17. data/lib/generators/active_fedora/config/solr/solr_generator.rb +1 -0
  18. data/lib/generators/active_fedora/config/solr/templates/jetty.yml +5 -0
  19. data/lib/generators/active_fedora/config/solr/templates/solr_conf/conf/schema.xml +1 -161
  20. data/lib/generators/active_fedora/config/solr/templates/solr_conf/conf/solrconfig.xml +16 -7
  21. data/lib/tasks/active_fedora_dev.rake +1 -1
  22. data/spec/fixtures/auditable.foxml.xml +110 -0
  23. data/spec/integration/base_spec.rb +7 -1
  24. data/spec/unit/auditable_spec.rb +31 -0
  25. data/spec/unit/base_delegate_spec.rb +74 -38
  26. data/spec/unit/base_spec.rb +6 -1
  27. data/spec/unit/has_and_belongs_to_many_collection_spec.rb +59 -0
  28. data/spec/unit/has_many_collection_spec.rb +26 -0
  29. metadata +96 -45
  30. checksums.yaml +0 -7
  31. data/solr/conf/schema.xml +0 -432
  32. data/solr/conf/solrconfig.xml +0 -158
data/.gitignore CHANGED
@@ -8,3 +8,4 @@ doc
8
8
  tmp
9
9
  Gemfile.lock
10
10
  jetty
11
+ bin
@@ -1,3 +1,19 @@
1
+ 6.1.0
2
+ Give a list of classes that decend from ActiveFedora::Base
3
+ ActiveFedora::Base.exists?(nil) now returns false. Fixes #56
4
+ Removed extraneous solr configs.
5
+ Deprecated get_values_from_datastream. Fixes #52
6
+ Added ActiveFedora::Base.decendants
7
+ Added some sensible defaults to the solrconfig. Removed comments about old fields.
8
+ active_fedora_model solr field corrected to be single-valued.
9
+ Fixed fields for solrconfig permissions.
10
+ Deprecated Attributes#update_datastream_attributes.
11
+ Delegate registry works with descendants of ActiveFedora::Base, not just direct subclasses. Fixes #59
12
+ New ActiveFedora::Auditable mixin - provides access to Fedora audit trail.
13
+ Fixed has and belongs to many, so it calls remove_relationship on the right object.
14
+ Added jetty.yml to solr generator to overwrite the Blacklight jetty.yml.
15
+ Upgrade to om 2.1.0.
16
+
1
17
  6.0.0
2
18
  New solr schema with descriptive field suffixes
3
19
  Added support for RDF lists
@@ -1,4 +1,4 @@
1
- "!https://travis-ci.org/projecthydra/active_fedora.png!":https://travis-ci.org/projecthydra/active_fedora
1
+ !https://travis-ci.org/projecthydra/active_fedora.png?branch=master!:https://travis-ci.org/projecthydra/active_fedora
2
2
 
3
3
  h2. Description
4
4
 
@@ -27,22 +27,27 @@ You can generate a model inheriting from ActiveFedora::Base.
27
27
 
28
28
  h2. Testing (this Gem)
29
29
 
30
- In order to run the RSpec tests, you need to have a copy of the ActiveFedora source code, and then run bundle install in the source directory.
30
+ In order to run the RSpec tests, you need to have a copy of the ActiveFedora source code, and then run bundle install in the source directory. Testing requires hydra-jetty, which contains version for Fedora and Solr. Setting up and maintaining hydra-jetty for the purposes of testing this gem is all accomplished via
31
31
 
32
32
  <pre>
33
33
  git clone https://github.com/projecthydra/active_fedora.git
34
34
  cd /wherever/active_fedora/is
35
35
  bundle install
36
- git submodule init
37
- git submodule update
38
36
  </pre>
39
37
 
40
- h3. Testing with Hudson Rake Task
38
+ h3. Using the continuous integration server
41
39
 
42
- The hudson rake task will spin up jetty, import the fixtures, and run the tests for you.
40
+ You can test ActiveFedora using the same process as our continuous integration server. To do that, unzip a copy
41
+ of hydra-jetty first. This includes copies of Fedora and Solr which are used during the testing process.
43
42
 
44
43
  <pre>
45
- rake active_fedora:hudson
44
+ rake jetty:unzip
45
+ </pre>
46
+
47
+ Once hydra-jetty is unzipped, the ci rake task will spin up jetty, import the fixtures, and run the tests for you.
48
+
49
+ <pre>
50
+ rake active_fedora:ci
46
51
  </pre>
47
52
 
48
53
  h3. Testing Manually
@@ -15,13 +15,13 @@ Gem::Specification.new do |s|
15
15
  s.required_ruby_version = '>= 1.9.3'
16
16
 
17
17
  s.add_dependency('rsolr')
18
- s.add_dependency('om', '~> 2.0.0')
18
+ s.add_dependency('om', '~> 2.1.0')
19
19
  s.add_dependency('nom-xml', '>=0.5.1')
20
20
  s.add_dependency("activeresource", '>= 3.0.0')
21
21
  s.add_dependency("activesupport", '>= 3.0.0')
22
22
  s.add_dependency("builder", '~> 3.0.0')
23
23
  s.add_dependency("mediashelf-loggable")
24
- s.add_dependency("rubydora", '~>1.5')
24
+ s.add_dependency("rubydora", '~>1.6')
25
25
  s.add_dependency("rdf")
26
26
  s.add_dependency("rdf-rdfxml", '~>1.0.0')
27
27
  s.add_dependency("deprecation")
@@ -26,6 +26,7 @@ module ActiveFedora #:nodoc:
26
26
  eager_autoload do
27
27
  autoload :Associations
28
28
  autoload :Attributes
29
+ autoload :Auditable
29
30
  autoload :Base
30
31
  autoload :ContentModel
31
32
  autoload :Callbacks
@@ -74,7 +74,7 @@ module ActiveFedora
74
74
  flatten_deeper(records).each do |record|
75
75
  raise_on_type_mismatch(record)
76
76
  add_record_to_target_with_callbacks(record) do |r|
77
- result &&= insert_record(record) unless @owner.new_record?
77
+ result &&= insert_record(record)
78
78
  end
79
79
  end
80
80
 
@@ -31,16 +31,25 @@ module ActiveFedora
31
31
 
32
32
  ### TODO save relationship
33
33
  @owner.add_relationship(@reflection.options[:property], record)
34
- if (@reflection.options[:inverse_of])
34
+
35
+ if @owner.new_record? and @reflection.options[:inverse_of]
36
+ logger.warn("has_and_belongs_to_many #{@reflection.inspect} is cowardly refusing to insert the inverse relationship into #{record}, because #{@owner} is not persisted yet.")
37
+ elsif @reflection.options[:inverse_of]
35
38
  record.add_relationship(@reflection.options[:inverse_of], @owner)
39
+ record.save
36
40
  end
37
- record.save
41
+
38
42
  return true
39
43
  end
40
44
 
41
45
  def delete_records(records)
42
46
  records.each do |r|
43
- r.remove_relationship(@reflection.options[:property], @owner)
47
+ @owner.remove_relationship(@reflection.options[:property], r)
48
+
49
+ if (@reflection.options[:inverse_of])
50
+ r.remove_relationship(@reflection.options[:inverse_of], @owner)
51
+ r.save
52
+ end
44
53
  end
45
54
  end
46
55
  end
@@ -31,6 +31,10 @@ module ActiveFedora
31
31
  end
32
32
 
33
33
  def insert_record(record, force = false, validate = true)
34
+ if @owner.new_record?
35
+ logger.warn("has_many #{@reflection.inspect} is cowardly refusing to insert a relationship into #{record}, because #{@owner} is not persisted yet.")
36
+ return true
37
+ end
34
38
  set_belongs_to_association_for(record)
35
39
  #force ? record.save! : record.save(:validate => validate)
36
40
  record.save
@@ -2,6 +2,10 @@ module ActiveFedora
2
2
  module Attributes
3
3
  extend ActiveSupport::Concern
4
4
  extend ActiveSupport::Autoload
5
+ extend Deprecation
6
+ self.deprecation_horizon = 'active-fedora 7.0.0'
7
+
8
+
5
9
  autoload :Serializers
6
10
 
7
11
  included do
@@ -60,6 +64,7 @@ module ActiveFedora
60
64
  # }
61
65
  # article.update_datastream_attributes( ds_values_hash )
62
66
  def update_datastream_attributes(params={}, opts={})
67
+ Deprecation.warn(Attributes, 'update_datastream_attributes is deprecated. Consider using delegate_to instead.', caller)
63
68
  result = params.dup
64
69
  params.each_pair do |dsid, ds_params|
65
70
  if datastreams.include?(dsid)
@@ -72,6 +77,7 @@ module ActiveFedora
72
77
  end
73
78
 
74
79
  def get_values_from_datastream(dsid,field_key,default=[])
80
+ Deprecation.warn(Attributes, 'get_values_from_datastream is deprecated. Consider using Datastream#get_values instead.', caller)
75
81
  if datastreams.include?(dsid)
76
82
  return datastreams[dsid].get_values(field_key,default)
77
83
  else
@@ -0,0 +1,9 @@
1
+ module ActiveFedora
2
+ module Auditable
3
+
4
+ def audit_trail
5
+ inner_object.audit_trail
6
+ end
7
+
8
+ end
9
+ end
@@ -1,6 +1,7 @@
1
1
  SOLR_DOCUMENT_ID = "id" unless (defined?(SOLR_DOCUMENT_ID) && !SOLR_DOCUMENT_ID.nil?)
2
2
  ENABLE_SOLR_UPDATES = true unless defined?(ENABLE_SOLR_UPDATES)
3
3
  require "digest"
4
+ require 'active_support/descendants_tracker'
4
5
 
5
6
  module ActiveFedora
6
7
 
@@ -315,6 +316,7 @@ module ActiveFedora
315
316
  Base.class_eval do
316
317
  include Attributes
317
318
  include ActiveFedora::Persistence
319
+ extend ActiveSupport::DescendantsTracker
318
320
  extend Model
319
321
  include Loggable
320
322
  include Indexing
@@ -27,13 +27,15 @@ module ActiveFedora
27
27
 
28
28
  module ClassMethods
29
29
  def delegates
30
- @delegates ||= {}
30
+ @local_delegates ||= {}
31
+ return @local_delegates unless superclass.respond_to?(:delegates) and value = superclass.delegates
32
+ @local_delegates = value.dup if @local_delegates.empty?
33
+ @local_delegates
31
34
  end
32
35
 
33
36
  def delegates= val
34
- @delegates = val
37
+ @local_delegates = val
35
38
  end
36
-
37
39
  # Provides a delegate class method to expose methods in metadata streams
38
40
  # as member of the base object. Pass the target datastream via the
39
41
  # <tt>:to</tt> argument. If you want to return a unique result, (e.g. string
@@ -14,7 +14,7 @@ module ActiveFedora
14
14
  m_time = Time.parse(m_time) unless m_time.is_a?(Time)
15
15
  Solrizer.set_field(solr_doc, 'system_create', c_time, :stored_sortable)
16
16
  Solrizer.set_field(solr_doc, 'system_modified', m_time, :stored_sortable)
17
- Solrizer.set_field(solr_doc, 'active_fedora_model', self.class.inspect, :symbol)
17
+ Solrizer.set_field(solr_doc, 'active_fedora_model', self.class.inspect, :stored_sortable)
18
18
  solr_doc.merge!(SOLR_DOCUMENT_ID.to_sym => pid)
19
19
  solrize_profile(solr_doc)
20
20
  end
@@ -3,10 +3,9 @@ module ActiveFedora
3
3
  class NokogiriDatastream < OmDatastream
4
4
  extend Deprecation
5
5
  def initialize(digital_object=nil, dsid=nil, options={})
6
+ Deprecation.warn(self.class, "NokogiriDatastream is deprecated and will be removed in hydra-head 7.0. Use OmDatastream insead.", caller(2))
6
7
  super
7
8
  end
8
- self.deprecation_horizon= "hydra-head 7.0"
9
- deprecation_deprecate :initialize
10
9
  end
11
10
  end
12
11
 
@@ -72,6 +72,7 @@ module ActiveFedora
72
72
  # @param[String] pid
73
73
  # @return[boolean]
74
74
  def exists?(pid)
75
+ return false if pid.nil? || pid.empty?
75
76
  inner = DigitalObject.find_or_initialize(self, pid)
76
77
  !inner.new?
77
78
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveFedora
2
- VERSION = "6.0.0"
2
+ VERSION = "6.1.0"
3
3
  end
@@ -5,6 +5,7 @@ module ActiveFedora
5
5
  source_root File.expand_path('../templates', __FILE__)
6
6
 
7
7
  def generate
8
+ copy_file('jetty.yml', 'config/jetty.yml')
8
9
  copy_file('solr.yml', 'config/solr.yml')
9
10
  directory('solr_conf', 'solr_conf')
10
11
  end
@@ -0,0 +1,5 @@
1
+ default:
2
+ jetty_port: 8983
3
+ java_opts:
4
+ - "-XX:MaxPermSize=128m"
5
+ - "-Xmx256m"
@@ -13,30 +13,6 @@
13
13
  <field name="lat" type="tdouble" stored="true" indexed="true" multiValued="false"/>
14
14
  <field name="lng" type="tdouble" stored="true" indexed="true" multiValued="false"/>
15
15
 
16
- <!--these fields are hard coded in places in hydra-head -->
17
- <field name="active_fedora_model_s" type="string" stored="true" indexed="true"/>
18
- <field name="object_profile_display" type="string" stored="true" indexed="true"/>
19
- <field name="has_model_s" type="string" stored="true" indexed="true"/>
20
- <field name="is_governed_by_s" type="string" stored="true" indexed="true"/>
21
-
22
- <!--
23
- These are hard coded in places in hydra-head, but we hope to fix that.
24
-
25
- <field name="inheritable_discover_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
26
- <field name="inheritable_read_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
27
- <field name="inheritable_edit_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
28
- <field name="inheritable_discover_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
29
- <field name="inheritable_read_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
30
- <field name="inheritable_edit_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
31
- <field name="read_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
32
- <field name="discover_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
33
- <field name="edit_access_person_t" type="string" stored="true" indexed="true" multiValued="true"/>
34
- <field name="read_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
35
- <field name="edit_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
36
- <field name="discover_access_group_t" type="string" stored="true" indexed="true" multiValued="true"/>
37
- -->
38
-
39
-
40
16
  <!-- NOTE: not all possible Solr field types are represented in the dynamic fields -->
41
17
 
42
18
  <!-- text (_t...) -->
@@ -173,152 +149,16 @@
173
149
  <!-- you must define copyField source and dest fields explicity or schemaBrowser doesn't work -->
174
150
  <field name="all_text_timv" type="text" stored="false" indexed="true" multiValued="true" termVectors="true" termPositions="true" termOffsets="true"/>
175
151
 
176
- <!-- deprecated fields from pre-Solr 4.0 pre-hydra 5.0 -->
177
- <!--
178
- <field name="marc_display" type="string" indexed="false" stored="true" multiValued="false"/>
179
- <field name="title_display" type="string" indexed="false" stored="true" multiValued="false"/>
180
- <field name="title_vern_display" type="string" indexed="false" stored="true" multiValued="false"/>
181
- <field name="subtitle_display" type="string" indexed="false" stored="true" multiValued="false"/>
182
- <field name="subtitle_vern_display" type="string" indexed="false" stored="true" multiValued="false"/>
183
- <field name="author_display" type="string" indexed="false" stored="true" multiValued="false"/>
184
- <field name="author_vern_display" type="string" indexed="false" stored="true" multiValued="false"/>
185
- -->
186
- <!-- these fields are also used for display, so they must be stored -->
187
- <!--
188
- <field name="isbn_t" type="text" indexed="true" stored="true" multiValued="true"/>
189
- <field name="language_facet" type="string" indexed="true" stored="true" multiValued="true" />
190
- <field name="subject_topic_facet" type="string" indexed="true" stored="true" multiValued="true" />
191
- <field name="subject_era_facet" type="string" indexed="true" stored="true" multiValued="true" />
192
- <field name="subject_geo_facet" type="string" indexed="true" stored="true" multiValued="true" />
193
- -->
194
- <!-- pub_date is used for facet and display so it must be indexed and stored -->
195
- <!--
196
- <field name="pub_date" type="string" indexed="true" stored="true" multiValued="true"/>
197
- -->
198
- <!-- pub_date sort uses new trie-based int fields, which are recommended for any int and are displayable, sortable, and range-quer
199
- we use 'tint' for faster range-queries. -->
200
- <!--
201
- <field name="pub_date_sort" type="tint" indexed="true" stored="true" multiValued="false"/>
202
- -->
203
- <!-- format is used for facet, display, and choosing which partial to use for the show view, so it must be stored and indexed -->
204
- <!--
205
- <field name="format" type="string" indexed="true" stored="true"/>
206
-
207
- <dynamicField name="*_i" type="int" indexed="true" stored="true"/>
208
- <dynamicField name="*_s" type="string" indexed="true" stored="true" multiValued="true"/>
209
- <dynamicField name="*_l" type="long" indexed="true" stored="true"/>
210
- <dynamicField name="*_t" type="text" indexed="true" stored="true" multiValued="true"/>
211
- <dynamicField name="*_txt" type="text_general" indexed="true" stored="true" multiValued="true"/>
212
- <dynamicField name="*_b" type="boolean" indexed="true" stored="true"/>
213
- <dynamicField name="*_f" type="float" indexed="true" stored="true"/>
214
- <dynamicField name="*_d" type="double" indexed="true" stored="true"/>
215
-
216
- <dynamicField name="ignored_*" type="ignored" multiValued="true"/>
217
- <dynamicField name="attr_*" type="text_general" indexed="true" stored="true" multiValued="true"/>
218
-
219
- <dynamicField name="random_*" type="random" />
220
-
221
- <dynamicField name="*_display" type="string" indexed="false" stored="true" multiValued="true" />
222
- <dynamicField name="*_facet" type="string" indexed="true" stored="true" multiValued="true" />
223
- <dynamicField name="*_sort" type="string" indexed="true" stored="false" multiValued="false" />
224
- <dynamicField name="*_unstem_search" type="text_general" indexed="true" stored="false" multiValued="true" />
225
- <dynamicField name="*spell" type="textSpell" indexed="true" stored="false" multiValued="true" />
226
- -->
227
- <!-- uncomment the following to ignore any fields that don't already match an existing
228
- field name or dynamic field, rather than reporting them as an error.
229
- alternately, change the type="ignored" to some other type e.g. "text" if you want
230
- unknown fields indexed and/or stored by default -->
231
- <!--dynamicField name="*" type="ignored" multiValued="true" /-->
232
-
233
- <!-- END hydra deprecated items -->
234
152
 
235
153
  </fields>
236
154
 
237
- <!-- START hydra deprecated items -->
238
- <!--
239
- <defaultSearchField>text</defaultSearchField>
240
- -->
241
- <!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
242
- <!--
243
- <solrQueryParser defaultOperator="AND"/>
244
-
245
- <copyField source="title_t" dest="title_unstem_search"/>
246
- <copyField source="subtitle_t" dest="subtitle_unstem_search"/>
247
- <copyField source="title_addl_t" dest="title_addl_unstem_search"/>
248
- <copyField source="title_added_entry_t" dest="title_added_entry_unstem_search"/>
249
- <copyField source="title_series_t" dest="title_series_unstem_search"/>
250
- <copyField source="author_t" dest="author_unstem_search"/>
251
- <copyField source="author_addl_t" dest="author_addl_unstem_search"/>
252
- <copyField source="subject_t" dest="subject_unstem_search"/>
253
- <copyField source="subject_addl_t" dest="subject_addl_unstem_search"/>
254
- <copyField source="subject_topic_facet" dest="subject_topic_unstem_search"/>
255
- -->
256
- <!-- sort fields -->
257
- <!--
258
- <copyField source="pub_date" dest="pub_date_sort"/>
259
- -->
260
-
261
- <!-- spellcheck fields -->
262
- <!-- default spell check; should match fields for default request handler -->
263
- <!-- it won't work with a copy of a copy field -->
264
- <!--
265
- <copyField source="*_t" dest="spell"/>
266
- <copyField source="*_facet" dest="spell"/>
267
- -->
268
- <!-- title spell check; should match fields for title request handler -->
269
- <!--
270
- <copyField source="title_t" dest="title_spell"/>
271
- <copyField source="subtitle_t" dest="title_spell"/>
272
- <copyField source="addl_titles_t" dest="title_spell"/>
273
- <copyField source="title_added_entry_t" dest="title_spell"/>
274
- <copyField source="title_series_t" dest="title_spell"/>
275
- -->
276
- <!-- author spell check; should match fields for author request handler -->
277
- <!--
278
- <copyField source="author_t" dest="author_spell"/>
279
- <copyField source="author_addl_t" dest="author_spell"/>
280
- -->
281
- <!-- subject spell check; should match fields for subject request handler -->
282
- <!--
283
- <copyField source="subject_topic_facet" dest="subject_spell"/>
284
- <copyField source="subject_t" dest="subject_spell"/>
285
- <copyField source="subject_addl_t" dest="subject_spell"/>
286
- -->
287
-
288
- <!-- OpenSearch query field should match request handler search fields -->
289
- <!--
290
- <copyField source="title_t" dest="opensearch_display"/>
291
- <copyField source="subtitle_t" dest="opensearch_display"/>
292
- <copyField source="addl_titles_t" dest="opensearch_display"/>
293
- <copyField source="title_added_entry_t" dest="opensearch_display"/>
294
- <copyField source="title_series_t" dest="opensearch_display"/>
295
- <copyField source="author_t" dest="opensearch_display"/>
296
- <copyField source="author_addl_t" dest="opensearch_display"/>
297
- <copyField source="subject_topic_facet" dest="opensearch_display"/>
298
- <copyField source="subject_t" dest="opensearch_display"/>
299
- <copyField source="subject_addl_t" dest="opensearch_display"/>
300
- -->
301
155
 
302
156
  <!-- Above, multiple source fields are copied to the [text] field.
303
157
  Another way to map multiple source fields to the same
304
158
  destination field is to use the dynamic field syntax.
305
159
  copyField also supports a maxChars to copy setting. -->
306
160
 
307
- <!-- <copyField source="*_t" dest="text" maxChars="3000"/> -->
308
- <!--
309
- <copyField source="*_s" dest="text"/>
310
- <copyField source="*_t" dest="text"/>
311
- <copyField source="*_facet" dest="text"/>
312
- -->
313
- <!-- copy name to alphaNameSort, a field designed for sorting by name -->
314
- <!-- <copyField source="name" dest="alphaNameSort"/> -->
315
-
316
- <!-- END hydra deprecated items -->
317
-
318
- <!-- copy fields; note that you must define copyField source and dest fields explicity or schemaBrowser doesn't work -->
319
- <!--
320
- <copyField source="some_field" dest="all_text_timv" />
321
- -->
161
+ <!-- <copyField source="*_tesim" dest="all_text_timv" maxChars="3000"/> -->
322
162
 
323
163
  <types>
324
164
  <fieldType name="string" class="solr.StrField" sortMissingLast="true" />