linked_rails 0.0.1 → 0.0.4.pre.ge1306665a

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.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -674
  3. data/app/controllers/linked_rails/actions/objects_controller.rb +9 -0
  4. data/app/controllers/linked_rails/bulk_controller.rb +71 -21
  5. data/app/controllers/linked_rails/enum_values_controller.rb +0 -42
  6. data/app/models/linked_rails/actions/item.rb +64 -55
  7. data/app/models/linked_rails/actions/list.rb +6 -31
  8. data/app/models/linked_rails/actions/object.rb +38 -0
  9. data/app/models/linked_rails/collection/configuration.rb +55 -0
  10. data/app/models/linked_rails/collection/filter.rb +1 -1
  11. data/app/models/linked_rails/collection/filter_field.rb +19 -2
  12. data/app/models/linked_rails/collection/filter_option.rb +1 -1
  13. data/app/models/linked_rails/collection/filterable.rb +6 -9
  14. data/app/models/linked_rails/collection/infinite.rb +113 -0
  15. data/app/models/linked_rails/collection/infinite_view.rb +1 -90
  16. data/app/models/linked_rails/collection/iri.rb +47 -43
  17. data/app/models/linked_rails/collection/iri_mapping.rb +15 -7
  18. data/app/models/linked_rails/collection/paginated.rb +46 -0
  19. data/app/models/linked_rails/collection/paginated_view.rb +1 -33
  20. data/app/models/linked_rails/collection/sortable.rb +1 -9
  21. data/app/models/linked_rails/collection/sorting.rb +1 -1
  22. data/app/models/linked_rails/collection/view.rb +51 -14
  23. data/app/models/linked_rails/collection.rb +53 -85
  24. data/app/models/linked_rails/creative_work.rb +1 -1
  25. data/app/models/linked_rails/entry_point.rb +8 -5
  26. data/app/models/linked_rails/enum_value.rb +40 -2
  27. data/app/models/linked_rails/form/field/association_input.rb +7 -1
  28. data/app/models/linked_rails/form/field/file_input.rb +1 -0
  29. data/app/models/linked_rails/form/field/resource_field.rb +2 -0
  30. data/{lib/linked_rails/enhancements/indexable/model.rb → app/models/linked_rails/form/field/url_input.rb} +3 -3
  31. data/app/models/linked_rails/form/field.rb +37 -13
  32. data/app/models/linked_rails/form/field_factory.rb +48 -18
  33. data/app/models/linked_rails/form/group.rb +4 -6
  34. data/app/models/linked_rails/form/page.rb +8 -4
  35. data/app/models/linked_rails/form.rb +16 -21
  36. data/app/models/linked_rails/manifest.rb +8 -2
  37. data/app/models/linked_rails/menus/item.rb +10 -13
  38. data/app/models/linked_rails/menus/list.rb +16 -7
  39. data/app/models/linked_rails/ontology/base.rb +3 -1
  40. data/app/models/linked_rails/ontology/class.rb +3 -3
  41. data/app/models/linked_rails/ontology.rb +5 -5
  42. data/app/models/linked_rails/property_query.rb +2 -0
  43. data/app/models/linked_rails/sequence.rb +4 -13
  44. data/app/models/linked_rails/shacl/property_shape.rb +1 -1
  45. data/app/models/linked_rails/web_page.rb +0 -4
  46. data/app/models/linked_rails/web_site.rb +0 -4
  47. data/app/models/linked_rails/widget.rb +4 -11
  48. data/app/policies/linked_rails/actions/object_policy.rb +11 -0
  49. data/app/policies/linked_rails/collection_policy.rb +2 -2
  50. data/app/serializers/linked_rails/actions/item_serializer.rb +5 -5
  51. data/app/serializers/linked_rails/actions/object_serializer.rb +9 -0
  52. data/app/serializers/linked_rails/collection/filter_field_serializer.rb +3 -2
  53. data/app/serializers/linked_rails/collection/filter_option_serializer.rb +1 -1
  54. data/app/serializers/linked_rails/collection/filter_serializer.rb +1 -1
  55. data/app/serializers/linked_rails/collection/sorting_serializer.rb +1 -1
  56. data/app/serializers/linked_rails/collection/view_serializer.rb +3 -3
  57. data/app/serializers/linked_rails/collection_serializer.rb +8 -7
  58. data/app/serializers/linked_rails/condition_serializer.rb +3 -3
  59. data/app/serializers/linked_rails/entry_point_serializer.rb +3 -3
  60. data/app/serializers/linked_rails/enum_value_serializer.rb +1 -0
  61. data/app/serializers/linked_rails/form/field/association_input_serializer.rb +1 -0
  62. data/app/serializers/linked_rails/form/field/file_input_serializer.rb +11 -0
  63. data/app/serializers/linked_rails/form/field_serializer.rb +3 -1
  64. data/app/serializers/linked_rails/form/group_serializer.rb +1 -1
  65. data/app/serializers/linked_rails/form/page_serializer.rb +1 -1
  66. data/app/serializers/linked_rails/menus/item_serializer.rb +3 -3
  67. data/app/serializers/linked_rails/menus/list_serializer.rb +1 -1
  68. data/app/serializers/linked_rails/ontology_serializer.rb +2 -2
  69. data/app/serializers/linked_rails/property_query_serializer.rb +7 -0
  70. data/app/serializers/linked_rails/sequence_serializer.rb +2 -5
  71. data/app/serializers/linked_rails/shacl/node_shape_serializer.rb +1 -1
  72. data/app/serializers/linked_rails/shacl/property_shape_serializer.rb +1 -1
  73. data/app/serializers/linked_rails/shacl/shape_serializer.rb +5 -5
  74. data/app/serializers/linked_rails/web_page_serializer.rb +3 -3
  75. data/app/serializers/linked_rails/web_site_serializer.rb +1 -1
  76. data/app/serializers/linked_rails/widget_serializer.rb +3 -3
  77. data/lib/generators/linked_rails/install/install_generator.rb +7 -8
  78. data/lib/generators/linked_rails/install/templates/README +7 -0
  79. data/lib/generators/linked_rails/install/templates/app_menu_list.rb +36 -7
  80. data/lib/generators/linked_rails/install/templates/application_menu_list.rb +40 -1
  81. data/lib/generators/linked_rails/install/templates/initializer.rb +1 -2
  82. data/lib/generators/linked_rails/install/templates/locales.yml +14 -0
  83. data/lib/generators/linked_rails/install/templates/rdf_serializers_initializer.rb +1 -1
  84. data/lib/generators/linked_rails/install/templates/vocab.rb +1 -0
  85. data/lib/generators/linked_rails/install/templates/vocab.yml +2 -2
  86. data/lib/generators/linked_rails/model/model_generator.rb +0 -1
  87. data/lib/generators/linked_rails/model/templates/controller.rb.tt +5 -1
  88. data/lib/generators/linked_rails/model/templates/form.rb.tt +3 -0
  89. data/lib/generators/linked_rails/model/templates/menu_list.rb.tt +15 -0
  90. data/lib/generators/linked_rails/model/templates/policy.rb.tt +13 -0
  91. data/lib/generators/linked_rails/model/templates/serializer.rb.tt +5 -1
  92. data/lib/linked_rails/active_response/controller/collections.rb +1 -1
  93. data/lib/linked_rails/active_response/controller/crud_defaults.rb +4 -4
  94. data/lib/linked_rails/active_response/controller/params.rb +10 -10
  95. data/lib/linked_rails/active_response/controller.rb +8 -18
  96. data/lib/linked_rails/active_response/responders/rdf.rb +19 -10
  97. data/lib/linked_rails/callable_variable.rb +1 -1
  98. data/lib/linked_rails/collection_params_parser.rb +93 -0
  99. data/lib/linked_rails/controller/actionable.rb +121 -0
  100. data/lib/linked_rails/controller/authorization.rb +6 -0
  101. data/lib/linked_rails/controller/default_actions/create.rb +52 -0
  102. data/lib/linked_rails/controller/default_actions/destroy.rb +42 -0
  103. data/lib/linked_rails/controller/default_actions/update.rb +43 -0
  104. data/lib/linked_rails/controller/delta.rb +78 -0
  105. data/lib/linked_rails/controller/error_handling.rb +11 -9
  106. data/lib/linked_rails/controller/rendering.rb +48 -0
  107. data/lib/linked_rails/controller.rb +24 -4
  108. data/lib/linked_rails/enhanceable.rb +1 -1
  109. data/lib/linked_rails/enhancements/creatable/controller.rb +1 -1
  110. data/lib/linked_rails/enhancements/destroyable/controller.rb +1 -1
  111. data/lib/linked_rails/enhancements/updatable/controller.rb +1 -1
  112. data/lib/linked_rails/enhancements.rb +0 -16
  113. data/lib/linked_rails/helpers/delta_helper.rb +26 -57
  114. data/lib/linked_rails/helpers/ontola_actions_helper.rb +2 -2
  115. data/lib/linked_rails/helpers/resource_helper.rb +4 -2
  116. data/lib/linked_rails/iri_mapper.rb +17 -39
  117. data/lib/linked_rails/middleware/error_handling.rb +51 -0
  118. data/lib/linked_rails/middleware/linked_data_params.rb +30 -151
  119. data/lib/linked_rails/model/actionable.rb +68 -0
  120. data/lib/linked_rails/model/collections.rb +201 -39
  121. data/lib/linked_rails/model/dirty.rb +7 -8
  122. data/lib/linked_rails/model/enhancements.rb +1 -6
  123. data/lib/linked_rails/model/filtering.rb +4 -6
  124. data/lib/linked_rails/model/indexable.rb +6 -16
  125. data/lib/linked_rails/model/iri.rb +28 -19
  126. data/lib/linked_rails/model/iri_mapping.rb +37 -8
  127. data/lib/linked_rails/model/menuable.rb +28 -0
  128. data/lib/linked_rails/model/serialization.rb +2 -15
  129. data/lib/linked_rails/model/singularable.rb +57 -0
  130. data/lib/linked_rails/model/sorting.rb +0 -5
  131. data/lib/linked_rails/model/tables.rb +26 -0
  132. data/lib/linked_rails/model.rb +17 -7
  133. data/lib/linked_rails/params_parser.rb +133 -55
  134. data/lib/linked_rails/policy/attribute_conditions.rb +2 -2
  135. data/lib/linked_rails/policy.rb +40 -46
  136. data/lib/linked_rails/railtie.rb +11 -0
  137. data/lib/linked_rails/rdf_error.rb +2 -2
  138. data/lib/linked_rails/renderers.rb +1 -0
  139. data/lib/linked_rails/routes.rb +38 -22
  140. data/lib/linked_rails/serializer/actionable.rb +27 -0
  141. data/lib/linked_rails/serializer/menuable.rb +31 -0
  142. data/lib/linked_rails/serializer/singularable.rb +26 -0
  143. data/lib/linked_rails/serializer.rb +28 -11
  144. data/lib/linked_rails/test_methods.rb +114 -0
  145. data/lib/linked_rails/translate.rb +31 -9
  146. data/lib/linked_rails/types/iri_type.rb +37 -0
  147. data/lib/linked_rails/uri_template.rb +30 -0
  148. data/lib/linked_rails/version.rb +1 -1
  149. data/lib/linked_rails/vocab.rb +9 -0
  150. data/lib/linked_rails.rb +30 -13
  151. data/lib/rails/welcome_controller.rb +3 -2
  152. data/lib/rdf/list.rb +9 -0
  153. data/lib/rdf/query_fix.rb +15 -0
  154. metadata +58 -33
  155. data/app/models/linked_rails/actions/default_actions/create.rb +0 -60
  156. data/app/models/linked_rails/actions/default_actions/destroy.rb +0 -45
  157. data/app/models/linked_rails/actions/default_actions/update.rb +0 -50
  158. data/app/models/linked_rails/actions/default_actions.rb +0 -17
  159. data/lib/generators/linked_rails/install/templates/application_action_list.rb +0 -3
  160. data/lib/generators/linked_rails/model/templates/action_list.rb.tt +0 -6
  161. data/lib/linked_rails/enhancements/actionable/model.rb +0 -71
  162. data/lib/linked_rails/enhancements/actionable/serializer.rb +0 -25
  163. data/lib/linked_rails/enhancements/creatable/action.rb +0 -15
  164. data/lib/linked_rails/enhancements/destroyable/action.rb +0 -15
  165. data/lib/linked_rails/enhancements/destroyable/routing.rb +0 -19
  166. data/lib/linked_rails/enhancements/menuable/model.rb +0 -36
  167. data/lib/linked_rails/enhancements/menuable/serializer.rb +0 -33
  168. data/lib/linked_rails/enhancements/route_concerns.rb +0 -56
  169. data/lib/linked_rails/enhancements/singularable/controller.rb +0 -43
  170. data/lib/linked_rails/enhancements/singularable/model.rb +0 -47
  171. data/lib/linked_rails/enhancements/singularable/serializer.rb +0 -28
  172. data/lib/linked_rails/enhancements/tableable/model.rb +0 -28
  173. data/lib/linked_rails/enhancements/updatable/action.rb +0 -15
  174. data/lib/linked_rails/enhancements/updatable/routing.rb +0 -20
@@ -5,12 +5,7 @@ module LinkedRails
5
5
  module Filterable
6
6
  include RDF::Serializers::DataTypeHelper
7
7
 
8
- attr_writer :default_filters, :filter, :unfiltered_collection
9
-
10
- def default_filters
11
- opts = @default_filters || association_class.try(:default_filters) || {}
12
- opts.respond_to?(:call) ? opts.call(parent) : opts
13
- end
8
+ attr_writer :filter, :unfiltered_collection
14
9
 
15
10
  def filter
16
11
  default_filters.merge(@filter || {})
@@ -56,9 +51,10 @@ module LinkedRails
56
51
  end
57
52
 
58
53
  def apply_filter(scope, key, values)
59
- filter = filter_options.fetch(key).try(:[], :filter)
54
+ filter = filter_options[key].try(:[], :filter)
60
55
 
61
56
  return filter.call(scope, values) if filter
57
+ return scope unless association_class.predicate_mapping.key?(key)
62
58
 
63
59
  scope.where(association_class.predicate_mapping[key].key => values)
64
60
  end
@@ -77,13 +73,14 @@ module LinkedRails
77
73
  klass: association_class,
78
74
  key: key,
79
75
  options_in: options[:values_in],
80
- options_array: options[:values]
76
+ options_array: options[:values],
77
+ visible: options[:visible]
81
78
  )
82
79
  end
83
80
 
84
81
  def sanitized_filter_value(key, value)
85
82
  mapping = association_class.predicate_mapping[key]
86
- datatype = mapping.is_a?(FastJsonapi::Relationship) ? RDF.xsd.anyURI : mapping.datatype
83
+ datatype = mapping.is_a?(FastJsonapi::Relationship) ? Vocab.xsd.anyURI : mapping&.datatype
87
84
  val = xsd_to_rdf(datatype, value)
88
85
  val.literal? ? val.object : val
89
86
  end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class Collection
5
+ module Infinite
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_accessor :before
10
+ end
11
+
12
+ def any?
13
+ return members_query.any? if members_query.is_a?(ActiveRecord::Relation)
14
+
15
+ count.positive?
16
+ end
17
+
18
+ def initialize(orignial = {})
19
+ attrs = orignial.with_indifferent_access
20
+ attrs[:before] = attrs[:before]&.map { |val| val.with_indifferent_access }
21
+ super(attrs)
22
+ end
23
+
24
+ def next
25
+ return if before.blank? || members.blank?
26
+
27
+ current_opts = {
28
+ collection: collection,
29
+ filter: filter
30
+ }
31
+ next_view = collection.view_with_opts(current_opts.merge(before: next_before_values))
32
+
33
+ next_view.iri if next_view.any?
34
+ end
35
+
36
+ def prev; end
37
+
38
+ def type
39
+ :infinite
40
+ end
41
+
42
+ private
43
+
44
+ def additional_statements(arel, index)
45
+ (preconditions(index) + [arel]).reduce { |or_acc, or_value| or_acc.and(or_value) }
46
+ end
47
+
48
+ def before_iri_opts
49
+ before&.map { |hash| "#{CGI.escape(hash[:key])}=#{hash[:value]}" }
50
+ end
51
+
52
+ def before_query
53
+ before_values.each_with_index.reduce(nil) do |acc, (value, index)|
54
+ arel = arel_table[value[:attribute]].send(value[:direction], value[:value])
55
+ acc.nil? ? arel : acc.or(additional_statements(arel, index))
56
+ end
57
+ end
58
+
59
+ def before_values
60
+ @before_values ||= before&.map do |value|
61
+ sorting = collection.sortings.detect { |s| s.key == value[:key] }
62
+ next if sorting.nil?
63
+
64
+ {
65
+ attribute: sorting.attribute_name,
66
+ direction: sorting.sort_direction,
67
+ key: value[:key],
68
+ value: value[:value]
69
+ }
70
+ end.compact
71
+ end
72
+
73
+ def iri_opts
74
+ {
75
+ 'before%5B%5D': before_iri_opts
76
+ }.merge(collection.iri_opts)
77
+ end
78
+
79
+ def iris_from_scope; end
80
+
81
+ def members_query
82
+ @members_query ||=
83
+ prepare_members(association_base)
84
+ .where(before_query)
85
+ .limit(page_size)
86
+ end
87
+
88
+ def next_before_values
89
+ last_record = members_query.last
90
+ before_values.map do |val|
91
+ value = last_record.send(val[:attribute])
92
+ value = value.utc.iso8601(6) if value.is_a?(Time)
93
+ {
94
+ key: val[:key],
95
+ value: value
96
+ }
97
+ end
98
+ end
99
+
100
+ def preconditions(index)
101
+ before_values[0...index].map do |v|
102
+ condition = arel_table[v[:attribute]].eq(v[:value])
103
+ condition = condition.or(arel_table[v[:attribute]].eq(nil)) if v[:direction] == :gt
104
+ condition
105
+ end
106
+ end
107
+
108
+ def sort_column
109
+ @sort_column ||= collection.sortings.last.sort_value.keys.first
110
+ end
111
+ end
112
+ end
113
+ end
@@ -3,96 +3,7 @@
3
3
  module LinkedRails
4
4
  class Collection
5
5
  class InfiniteView < LinkedRails.collection_view_class
6
- attr_accessor :before
7
-
8
- def initialize(orignial = {})
9
- attrs = orignial.with_indifferent_access
10
- attrs[:before] = attrs[:before]&.map { |val| val.with_indifferent_access }
11
- super(attrs)
12
- end
13
-
14
- def next
15
- return if before.blank? || members.blank?
16
-
17
- current_opts = {
18
- collection: collection,
19
- filter: filter
20
- }
21
- next_view = collection.view_with_opts(current_opts.merge(before: next_before_values))
22
-
23
- next_view.iri if next_view.count.positive?
24
- end
25
-
26
- def prev; end
27
-
28
- def type
29
- :infinite
30
- end
31
-
32
- private
33
-
34
- def additional_statements(arel, index)
35
- (preconditions(index) + [arel]).reduce { |or_acc, or_value| or_acc.and(or_value) }
36
- end
37
-
38
- def before_iri_opts
39
- before&.map { |hash| "#{CGI.escape(hash[:key])}=#{hash[:value]}" }
40
- end
41
-
42
- def before_query
43
- before_values.each_with_index.reduce(nil) do |acc, (value, index)|
44
- arel = arel_table[value[:attribute]].send(value[:direction], value[:value])
45
- acc.nil? ? arel : acc.or(additional_statements(arel, index))
46
- end
47
- end
48
-
49
- def before_values
50
- @before_values ||= before&.map do |value|
51
- sorting = collection.sortings.detect { |s| s.key == value[:key] }
52
- {
53
- attribute: sorting.attribute_name,
54
- direction: sorting.sort_direction,
55
- key: value[:key],
56
- value: value[:value]
57
- }
58
- end
59
- end
60
-
61
- def iri_opts
62
- {
63
- 'before%5B%5D': before_iri_opts
64
- }.merge(collection.iri_opts)
65
- end
66
-
67
- def members_query
68
- prepare_members(association_base)
69
- .where(before_query)
70
- .limit(page_size)
71
- end
72
-
73
- def next_before_values
74
- last_record = members.last
75
- before_values.map do |val|
76
- value = last_record.send(val[:attribute])
77
- value = value.utc.iso8601(6) if value.is_a?(Time)
78
- {
79
- key: val[:key],
80
- value: value
81
- }
82
- end
83
- end
84
-
85
- def preconditions(index)
86
- before_values[0...index].map do |v|
87
- condition = arel_table[v[:attribute]].eq(v[:value])
88
- condition = condition.or(arel_table[v[:attribute]].eq(nil)) if v[:direction] == :gt
89
- condition
90
- end
91
- end
92
-
93
- def sort_column
94
- @sort_column ||= collection.sortings.last.sort_value.keys.first
95
- end
6
+ include LinkedRails::Collection::Infinite
96
7
  end
97
8
  end
98
9
  end
@@ -2,55 +2,45 @@
2
2
 
3
3
  module LinkedRails
4
4
  class Collection
5
- module Iri
6
- extend ActiveSupport::Concern
5
+ module IRI
6
+ DEFAULT_IRI_TEMPLATE_KEYS = %i[before%5B%5D display filter%5B%5D page page_size sort%5B%5D table_type title type].freeze
7
7
 
8
- included do
9
- attr_writer :iri_template
10
- end
8
+ extend ActiveSupport::Concern
11
9
 
12
10
  def iri_opts
13
- opts = {}
14
- iri_opts_add(opts, :display, display) if @display
15
- iri_opts_add(opts, :title, title) if @title
16
- iri_opts_add(opts, :type, type) if @type
17
- iri_opts_add(opts, :page_size, page_size) if @page_size
18
- iri_opts_add(opts, :'filter%5B%5D', filter_iri_opts)
19
- iri_opts_add(opts, :'sort%5B%5D', sort_iri_opts)
20
- opts
21
- end
22
-
23
- def iri_template
24
- @iri_template ||=
25
- URITemplate.new(
26
- [
27
- LinkedRails.iri(
28
- path: [parent&.root_relative_iri&.to_s&.split('?')&.first, association_class.route_key].join('/')
29
- ),
30
- "{?#{self.class.iri_template_parsed_keys}}"
31
- ].join('')
32
- )
11
+ {
12
+ parent_iri: parent_iri,
13
+ display: @display,
14
+ table_type: @table_type,
15
+ title: @title,
16
+ type: @type,
17
+ page_size: @page_size,
18
+ filter: self.class.filter_iri_opts(@filter),
19
+ route_key: route_key,
20
+ sort: self.class.sort_iri_opts(@sort)
21
+ }.compact
33
22
  end
34
23
 
35
24
  def iri_template_opts
36
- opts = iri_opts.with_indifferent_access.slice(*self.class.iri_template_keys)
25
+ opts = iri_opts.with_indifferent_access.slice(*(DEFAULT_IRI_TEMPLATE_KEYS + iri_template_keys))
37
26
  Hash[opts.keys.map { |key| [CGI.unescape(key).sub('[]', ''), opts[key]] }].to_param
38
27
  end
39
28
 
40
- def filter_iri_opts
41
- @filter&.map do |key, values|
42
- predicate = key.is_a?(RDF::URI) ? key : association_class.predicate_for_key(key)
43
-
44
- values.map { |value| "#{CGI.escape(predicate.to_s)}=#{CGI.escape(value.to_s)}" }
45
- end&.flatten
29
+ def serialized_iri_template
30
+ iri_template
31
+ .to_s
32
+ .gsub('{route_key}', iri_template_route_key)
33
+ .gsub('{/parent_iri*}', iri_template_parent_iri)
46
34
  end
47
35
 
48
- def iri_opts_add(opts, key, value)
49
- opts[key] = value if value.present?
36
+ private
37
+
38
+ def iri_template_parent_iri
39
+ parent&.iri&.to_s&.split('?')&.first || LinkedRails.iri
50
40
  end
51
41
 
52
- def sort_iri_opts
53
- sort&.map { |s| "#{CGI.escape(s[:key].to_s)}=#{s[:direction]}" }
42
+ def iri_template_route_key
43
+ route_key.to_s
54
44
  end
55
45
 
56
46
  class_methods do
@@ -58,15 +48,29 @@ module LinkedRails
58
48
  [super, Vocab.as.Collection]
59
49
  end
60
50
 
61
- def iri_template_keys
62
- @iri_template_keys ||= %i[before%5B%5D display filter%5B%5D page page_size sort%5B%5D title type]
51
+ def filter_iri_opts(filters)
52
+ return nil if filters.blank?
53
+
54
+ Hash[
55
+ filters.map do |key, values|
56
+ predicate = key.is_a?(RDF::URI) ? key : association_class.predicate_for_key(key)
57
+ [predicate, values]
58
+ end
59
+ ]
60
+ end
61
+
62
+ def generate_iri_template(iri_template_keys)
63
+ URITemplate.new("{/parent_iri*}/{route_key}{?#{parse_iri_template_keys(iri_template_keys)}}")
63
64
  end
64
65
 
65
- def iri_template_parsed_keys
66
- @iri_template_parsed_keys ||=
67
- iri_template_keys
68
- .map { |k| k.to_s.ends_with?('%5B%5D') ? "#{k}*" : k.to_s }
69
- .join(',')
66
+ def parse_iri_template_keys(keys)
67
+ (DEFAULT_IRI_TEMPLATE_KEYS + keys).map { |k| k.to_s.ends_with?('%5B%5D') ? "#{k}*" : k.to_s }.join(',')
68
+ end
69
+
70
+ def sort_iri_opts(sortings)
71
+ return nil if sortings.blank?
72
+
73
+ Hash[sortings.map { |s| [s[:key], s[:direction]] }]
70
74
  end
71
75
  end
72
76
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  module LinkedRails
4
4
  class Collection
5
- module IriMapping
5
+ module IRIMapping
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  class_methods do
9
9
  def collection_or_view(options, params)
10
- parser = params_parser_class.new(params)
11
- collection = new(options.merge(collection_params(parser)))
12
- view_params = collection_view_params(parser)
10
+ params_parser = params_parser_class.new(params)
11
+ collection = new(**merge_collection_opts(options, params_parser))
12
+ view_params = collection_view_params(params_parser)
13
13
 
14
14
  view_params.present? ? collection&.view_with_opts(view_params) : collection
15
15
  end
@@ -20,12 +20,20 @@ module LinkedRails
20
20
  parser.collection_params
21
21
  end
22
22
 
23
- def collection_view_params(parser)
24
- parser.collection_view_params
23
+ def collection_view_params(params_parser)
24
+ params_parser.collection_view_params
25
+ end
26
+
27
+ def merge_collection_opts(options, params_parser)
28
+ transformed_options = options.transform_keys do |key|
29
+ LinkedRails::Model::Collections::COLLECTION_CUSTOMIZABLE_OPTIONS.key?(key.to_sym) ? "default_#{key}" : key
30
+ end
31
+
32
+ transformed_options.merge(collection_params(params_parser))
25
33
  end
26
34
 
27
35
  def params_parser_class
28
- LinkedRails::ParamsParser
36
+ LinkedRails::CollectionParamsParser
29
37
  end
30
38
  end
31
39
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LinkedRails
4
+ class Collection
5
+ module Paginated
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_accessor :page
10
+ end
11
+
12
+ def next
13
+ return if page.nil? || page.to_i >= (total_page_count || 0)
14
+
15
+ iri_with_root(root_relative_iri(page: page.to_i + 1))
16
+ end
17
+
18
+ def prev
19
+ return if page.nil? || page.to_i <= 1
20
+
21
+ iri_with_root(root_relative_iri(page: page.to_i - 1))
22
+ end
23
+
24
+ private
25
+
26
+ def iri_opts
27
+ {
28
+ page: page
29
+ }.merge(collection.iri_opts)
30
+ end
31
+
32
+ def members_query
33
+ @members_query ||=
34
+ prepare_members(association_base)
35
+ .page(page)
36
+ .per(page_size)
37
+ end
38
+
39
+ def prepare_members(scope)
40
+ return super unless scope.is_a?(Array) && !scope.is_a?(Kaminari::PaginatableArray)
41
+
42
+ Kaminari.paginate_array(super)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -3,39 +3,7 @@
3
3
  module LinkedRails
4
4
  class Collection
5
5
  class PaginatedView < LinkedRails.collection_view_class
6
- attr_accessor :page
7
-
8
- def next
9
- return if page.nil? || page.to_i >= (total_page_count || 0)
10
-
11
- iri_with_root(root_relative_iri(page: page.to_i + 1))
12
- end
13
-
14
- def prev
15
- return if page.nil? || page.to_i <= 1
16
-
17
- iri_with_root(root_relative_iri(page: page.to_i - 1))
18
- end
19
-
20
- private
21
-
22
- def iri_opts
23
- {
24
- page: page
25
- }.merge(collection.iri_opts)
26
- end
27
-
28
- def members_query
29
- prepare_members(association_base)
30
- .page(page)
31
- .per(page_size)
32
- end
33
-
34
- def prepare_members(scope)
35
- return super unless scope.is_a?(Array) && !scope.is_a?(Kaminari::PaginatableArray)
36
-
37
- Kaminari.paginate_array(super)
38
- end
6
+ include LinkedRails::Collection::Paginated
39
7
  end
40
8
  end
41
9
  end
@@ -4,7 +4,7 @@ module LinkedRails
4
4
  class Collection
5
5
  module Sortable
6
6
  attr_accessor :sort
7
- attr_writer :default_sortings, :sort_options
7
+ attr_writer :sort_options
8
8
 
9
9
  def default_before_value
10
10
  sortings.map do |sorting|
@@ -15,14 +15,6 @@ module LinkedRails
15
15
  end
16
16
  end
17
17
 
18
- def default_sortings
19
- opts =
20
- @default_sortings ||
21
- association_class.try(:default_sortings) ||
22
- [{key: Vocab.schema.dateCreated, direction: :desc}]
23
- opts.respond_to?(:call) ? opts.call(parent) : opts
24
- end
25
-
26
18
  def parsed_sort_values
27
19
  sortings.map(&:sort_value)
28
20
  end
@@ -33,7 +33,7 @@ module LinkedRails
33
33
  end
34
34
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
35
35
 
36
- def iri(_opts = {})
36
+ def iri(**_opts)
37
37
  self
38
38
  end
39
39
 
@@ -8,14 +8,14 @@ module LinkedRails
8
8
  include LinkedRails::Model
9
9
 
10
10
  attr_accessor :collection, :filter
11
- delegate :apply_scope, :association_base, :association_class, :default_page_size, :display,
11
+ delegate :apply_scope, :association_base, :association_class, :default_page_size, :display, :include_members,
12
12
  :parent, :policy, :total_page_count, :unfiltered_collection, :user_context, to: :collection
13
13
  delegate :count, to: :members
14
14
 
15
15
  alias id iri
16
16
 
17
- def root_relative_iri(opts = {})
18
- collection.unfiltered.root_relative_iri(iri_opts.merge(opts))
17
+ def root_relative_iri(**opts)
18
+ collection.unfiltered.root_relative_iri(**iri_opts.merge(opts))
19
19
  end
20
20
 
21
21
  def member_sequence
@@ -28,7 +28,7 @@ module LinkedRails
28
28
  end
29
29
 
30
30
  def members
31
- @members ||= raw_members
31
+ @members ||= include_members ? members_array : iris_from_members
32
32
  end
33
33
 
34
34
  def members_iri
@@ -42,9 +42,7 @@ module LinkedRails
42
42
  end
43
43
 
44
44
  def preview_includes
45
- return {member_sequence: {}} unless association_class.include_in_collection?
46
-
47
- {member_sequence: {members: association_class.preview_includes}}
45
+ include_members ? {member_sequence: :members} : %i[member_sequence]
48
46
  end
49
47
 
50
48
  def title
@@ -62,6 +60,39 @@ module LinkedRails
62
60
  @arel_table ||= association_class.arel_table
63
61
  end
64
62
 
63
+ def iris_from_members
64
+ iris_from_scope || iris_from_records
65
+ end
66
+
67
+ def iris_from_records
68
+ members_query.map(&:iri)
69
+ end
70
+
71
+ def iris_from_scope
72
+ return unless iris_from_scope?
73
+
74
+ association_class.try(:iris_from_scope, members_query)
75
+ end
76
+
77
+ def iris_from_scope?
78
+ members_query.is_a?(ActiveRecord::Relation) && !polymorphic_collection?
79
+ end
80
+
81
+ def members_array
82
+ members_query.to_a
83
+ end
84
+
85
+ def polymorphic_collection?
86
+ column = association_class.inheritance_column
87
+ polymorphic = association_class.columns_hash.include?(column)
88
+ return false unless polymorphic
89
+
90
+ return true if association_class.descends_from_active_record?
91
+
92
+ members_query.where_values_hash.include?(column) &&
93
+ members_query.where_values_hash[column] != association_class.to_s
94
+ end
95
+
65
96
  def prepare_members(scope)
66
97
  if scope.respond_to?(:preload) && association_class.try(:includes_for_serializer)
67
98
  scope = scope.preload(association_class.includes_for_serializer)
@@ -69,24 +100,20 @@ module LinkedRails
69
100
  scope
70
101
  end
71
102
 
72
- def raw_members
73
- @raw_members ||= members_query.to_a
74
- end
75
-
76
103
  class << self
77
104
  def iri
78
105
  [super, Vocab.as.CollectionPage]
79
106
  end
80
107
 
81
- def new(opts = {})
108
+ def new(**opts)
82
109
  type = opts.delete(:type)&.to_sym
83
110
  return super if type.nil?
84
111
 
85
112
  case type
86
113
  when :paginated
87
- LinkedRails.collection_paginated_view_class.new(opts)
114
+ collection_paginated_view_class.new(**opts)
88
115
  when :infinite
89
- LinkedRails.collection_infinite_view_class.new(opts)
116
+ collection_infinite_view_class.new(**opts)
90
117
  else
91
118
  raise ActionController::BadRequest, "'#{type}' is not a valid collection type"
92
119
  end
@@ -95,6 +122,16 @@ module LinkedRails
95
122
  def policy_class
96
123
  LinkedRails::Collection::ViewPolicy
97
124
  end
125
+
126
+ private
127
+
128
+ def collection_paginated_view_class
129
+ LinkedRails.collection_paginated_view_class
130
+ end
131
+
132
+ def collection_infinite_view_class
133
+ LinkedRails.collection_infinite_view_class
134
+ end
98
135
  end
99
136
  end
100
137
  end