forest_admin_datasource_customizer 1.0.0.pre.beta.87 → 1.0.0.pre.beta.89

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: 427568d30553834fb7bc1f0728505c6ba7f75e72e74e9640672d0c2217d1e573
4
- data.tar.gz: 1561de136ccf71999933f3eb57c2b82424671999cb43a043b898e3fb426f750b
3
+ metadata.gz: d7e91993e1b735852ac34b459c724148edc5a3f2233f3bbb689740c1c8d2e5a4
4
+ data.tar.gz: 1791a150215a1a7f5f71337f9a7a6e8c98bd751e8a68a005dd1fee13002ab28c
5
5
  SHA512:
6
- metadata.gz: f9c582e66908f4aeabfbdd1de5d40b0ef6b79286530567d6077c8784af802dc06dd390a7835a12c21328abc94bd1ea2b6a72a47e781a69d8805b57156a64b971
7
- data.tar.gz: 2336895e724b81fa17e1f4c2c589d88b151c636c843daea2735148864edfe9f81a88dfa59709ebbe95998322ceab690b81dbaae111162c372c135791e5b32d5c
6
+ metadata.gz: 1582b606c627d2c3892f8f4ace39afa32cb213559a2f306296601000549c901a4cfeed752b38faf54efb60eca0d473bf5797b9d157630be72b3a41f0c6e1905e
7
+ data.tar.gz: c925fd3de6a66c317f0296059b16d77fbd22f3ea9462a3597bac0cb6b8df9f33917551ec48bdef1a1aad04122dc1a729c9845a300808e4db79d7869b4e4ec07f
@@ -5,7 +5,7 @@ module ForestAdminDatasourceCustomizer
5
5
 
6
6
  attr_reader :datasource, :schema, :search, :early_computed, :late_computed, :action, :relation, :late_op_emulate,
7
7
  :early_op_emulate, :validation, :sort, :rename_field, :publication, :write, :chart, :hook, :segment,
8
- :binary, :override
8
+ :binary, :override, :lazy_join
9
9
 
10
10
  def initialize(datasource)
11
11
  @customizations = []
@@ -19,6 +19,8 @@ module ForestAdminDatasourceCustomizer
19
19
  last = @early_op_emulate = DatasourceDecorator.new(last, OperatorsEmulate::OperatorsEmulateCollectionDecorator)
20
20
  last = DatasourceDecorator.new(last, OperatorsEquivalence::OperatorsEquivalenceCollectionDecorator)
21
21
  last = @relation = DatasourceDecorator.new(last, Relation::RelationCollectionDecorator)
22
+ # lazy join is just before relation, to avoid relations to do useless stuff
23
+ last = @lazy_join = DatasourceDecorator.new(last, LazyJoin::LazyJoinCollectionDecorator)
22
24
  last = @late_computed = DatasourceDecorator.new(last, Computed::ComputeCollectionDecorator)
23
25
  last = @late_op_emulate = DatasourceDecorator.new(last, OperatorsEmulate::OperatorsEmulateCollectionDecorator)
24
26
  last = DatasourceDecorator.new(last, OperatorsEquivalence::OperatorsEquivalenceCollectionDecorator)
@@ -0,0 +1,129 @@
1
+ module ForestAdminDatasourceCustomizer
2
+ module Decorators
3
+ module LazyJoin
4
+ class LazyJoinCollectionDecorator < ForestAdminDatasourceToolkit::Decorators::CollectionDecorator
5
+ include ForestAdminDatasourceToolkit::Decorators
6
+ include ForestAdminDatasourceToolkit::Components::Query
7
+ include ForestAdminDatasourceToolkit::Components::Query::ConditionTree
8
+
9
+ def list(caller, filter, projection)
10
+ simplified_projection = get_projection_without_useless_joins(projection)
11
+ refined_filter = refine_filter(caller, filter)
12
+ records = child_collection.list(caller, refined_filter, simplified_projection)
13
+
14
+ apply_joins_on_records(projection, simplified_projection, records)
15
+ end
16
+
17
+ def aggregate(caller, filter, aggregation, limit = nil)
18
+ refined_filter = refine_filter(caller, filter)
19
+ replaced = {}
20
+ refined_aggregation = aggregation.replace_fields do |field_name|
21
+ if useless_join?(field_name.split(':')[0], aggregation.projection)
22
+ new_field_name = get_foreign_key_for_projection(field_name)
23
+ replaced[new_field_name] = field_name
24
+
25
+ new_field_name
26
+ else
27
+ field_name
28
+ end
29
+ end
30
+
31
+ results = child_collection.aggregate(caller, refined_filter, refined_aggregation, limit)
32
+
33
+ apply_joins_on_aggregate_result(aggregation, refined_aggregation, results, replaced)
34
+ end
35
+
36
+ def refine_filter(_caller, filter = nil)
37
+ filter&.override(
38
+ condition_tree: filter.condition_tree&.replace_leafs do |leaf|
39
+ if useless_join?(leaf.field.split(':')[0], filter.condition_tree.projection)
40
+ leaf.override(field: get_foreign_key_for_projection(leaf.field))
41
+ else
42
+ leaf
43
+ end
44
+ end
45
+ )
46
+ end
47
+
48
+ private
49
+
50
+ def get_foreign_key_for_projection(field_name)
51
+ relation_name = field_name.split(':')[0]
52
+ relation_schema = schema[:fields][relation_name]
53
+
54
+ relation_schema.foreign_key
55
+ end
56
+
57
+ def useless_join?(relation_name, projection)
58
+ relation_schema = schema[:fields][relation_name]
59
+ sub_projection = projection.relations[relation_name]
60
+
61
+ relation_schema.type == 'ManyToOne' &&
62
+ sub_projection.size == 1 &&
63
+ sub_projection[0] == relation_schema.foreign_key_target
64
+ end
65
+
66
+ def get_projection_without_useless_joins(projection)
67
+ new_projection = Projection.new(projection)
68
+
69
+ projection.relations.each do |relation_name, relation_projection|
70
+ next unless useless_join?(relation_name, projection)
71
+
72
+ # remove foreign key target from projection
73
+ new_projection.delete("#{relation_name}:#{relation_projection[0]}")
74
+
75
+ # add foreign keys to projection
76
+ fk_field = get_foreign_key_for_projection("#{relation_name}:#{relation_projection[0]}")
77
+ new_projection << fk_field
78
+ end
79
+
80
+ new_projection
81
+ end
82
+
83
+ def apply_joins_on_records(initial_projection, requested_projection, records)
84
+ return records if initial_projection == requested_projection
85
+
86
+ projections_to_add = Projection.new(initial_projection.reject do |field|
87
+ requested_projection.include?(field)
88
+ end)
89
+ projections_to_rm = Projection.new(requested_projection.reject { |field| initial_projection.include?(field) })
90
+
91
+ records.each do |record|
92
+ # add to record relation:id
93
+ projections_to_add.relations.each do |relation_name, relation_projection|
94
+ relation_schema = schema[:fields][relation_name]
95
+
96
+ if relation_schema && relation_schema.type == 'ManyToOne'
97
+ fk_value = record[get_foreign_key_for_projection("#{relation_name}:#{relation_projection[0]}")]
98
+ record[relation_name] = fk_value.nil? ? nil : { relation_projection[0] => fk_value }
99
+ end
100
+ end
101
+
102
+ # remove foreign keys
103
+ projections_to_rm.each { |field| record.delete(field) }
104
+ end
105
+
106
+ records
107
+ end
108
+
109
+ def apply_joins_on_aggregate_result(initial_aggregation, requested_aggregation, results, fields_to_replace)
110
+ return result if initial_aggregation == requested_aggregation
111
+
112
+ results.each do |result|
113
+ group = {}
114
+ result['group'].each do |field, value|
115
+ if fields_to_replace.include?(field)
116
+ group[fields_to_replace[field]] = value
117
+ else
118
+ group[field] = value
119
+ end
120
+ end
121
+ result['group'] = group
122
+ end
123
+
124
+ results
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -1,3 +1,3 @@
1
1
  module ForestAdminDatasourceCustomizer
2
- VERSION = "1.0.0-beta.87"
2
+ VERSION = "1.0.0-beta.89"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_datasource_customizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.beta.87
4
+ version: 1.0.0.pre.beta.89
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2025-01-06 00:00:00.000000000 Z
12
+ date: 2025-01-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -116,6 +116,7 @@ files:
116
116
  - lib/forest_admin_datasource_customizer/decorators/hook/context/hook_context.rb
117
117
  - lib/forest_admin_datasource_customizer/decorators/hook/hook_collection_decorator.rb
118
118
  - lib/forest_admin_datasource_customizer/decorators/hook/hooks.rb
119
+ - lib/forest_admin_datasource_customizer/decorators/lazy_join/lazy_join_collection_decorator.rb
119
120
  - lib/forest_admin_datasource_customizer/decorators/operators_emulate/operators_emulate_collection_decorator.rb
120
121
  - lib/forest_admin_datasource_customizer/decorators/operators_equivalence/operators_equivalence_collection_decorator.rb
121
122
  - lib/forest_admin_datasource_customizer/decorators/override/context/create_override_customization_context.rb