forest_admin_datasource_toolkit 1.0.0.pre.beta.23 → 1.0.0.pre.beta.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 786b58c3bc21c7187d7a95025aae6229de6c04bac42549cede55f060be797d86
4
- data.tar.gz: 477ffdc3ed1eba5e5240e641741f9f7cbd311373e35594438ccc452584a75830
3
+ metadata.gz: a6db15a9f9827fdef57eb3a018ec0c3a9851a5ab131f26b38d2792fc12cb897d
4
+ data.tar.gz: 83ed4a24c607297af411ec2bbeacf739bb2c9f5c6b611343885a7237abb1deb6
5
5
  SHA512:
6
- metadata.gz: 46282da2e6d7221c853d234d382a3712a4fcb0e0340c06f93ba97f2a9ca26967a0adc0e153e6b904dfe39c4aaadcb31ffe0a3731ae6a097e3520120dbdaa0e16
7
- data.tar.gz: 52c33562da9679ea958fec285158dc6c12f5fb7ff9a3076f2724951bae500e99debb10925a562add7daeab4d749102494b46c6a33eaaaee22e54c5fb4c861984
6
+ metadata.gz: 2169823cdaa62b57be4fbef2cbd5986c4576d43ea063425ab741a9abd58af0b83b17881cad854f1e2ec6a3fe8de1006e589842fa6cfe052394252748e4d4ad53
7
+ data.tar.gz: fbc3374aefaeda605d14e882e9a988142d9a5e43c3d147546bbd1cfa17c6978429f953367e9588c02d47684146c41a32f664887d4d30205cbc228698654f3d0b
@@ -1,6 +1,6 @@
1
1
  module ForestAdminDatasourceToolkit
2
2
  class Collection < Components::Contracts::CollectionContract
3
- attr_accessor :fields, :segments
3
+ attr_accessor :segments
4
4
 
5
5
  attr_reader :actions,
6
6
  :charts,
@@ -17,13 +17,17 @@ module ForestAdminDatasourceToolkit
17
17
  @datasource = datasource
18
18
  @name = name
19
19
  @native_driver = native_driver
20
- @fields = {}
21
- @schema = {}
22
- @fields = {}
20
+ @schema = {
21
+ fields: {}
22
+ }
23
23
  @actions = {}
24
24
  @segments = {}
25
25
  @charts = {}
26
26
  @searchable = false
27
+ @countable = false
28
+ end
29
+
30
+ def enable_count
27
31
  @countable = true
28
32
  end
29
33
 
@@ -35,10 +39,14 @@ module ForestAdminDatasourceToolkit
35
39
  @searchable
36
40
  end
37
41
 
42
+ def fields
43
+ @schema[:fields]
44
+ end
45
+
38
46
  def add_field(name, field)
39
- raise Exceptions::ForestException, "Field #{name} already defined in collection" if @fields.key?(name)
47
+ raise Exceptions::ForestException, "Field #{name} already defined in collection" if @schema[:fields].key?(name)
40
48
 
41
- @fields[name] = field
49
+ @schema[:fields][name] = field
42
50
  end
43
51
 
44
52
  def add_fields(fields)
@@ -10,7 +10,7 @@ module ForestAdminDatasourceToolkit
10
10
  raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
11
11
  end
12
12
 
13
- def collection(name)
13
+ def get_collection(name)
14
14
  raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
15
15
  end
16
16
 
@@ -22,7 +22,7 @@ module ForestAdminDatasourceToolkit
22
22
  raise ForestException, 'Collection must have at least one primary key' if primary_key_names.empty?
23
23
 
24
24
  primary_key_names.each do |name|
25
- operators = collection.fields[name].filter_operators
25
+ operators = collection.schema[:fields][name].filter_operators
26
26
  unless operators.include?(Operators::EQUAL) || operators.include?(Operators::IN)
27
27
  raise ForestException, "Field '#{name}' must support operators: ['Equal', 'In']"
28
28
  end
@@ -54,15 +54,15 @@ module ForestAdminDatasourceToolkit
54
54
  def self.previous_interval(duration)
55
55
  interval(
56
56
  lambda { |now|
57
- duration == 'quarter' ? now.prev_quarter : (now - 1.send(duration)).send("beginning_of_#{duration}")
57
+ duration == 'quarter' ? now.prev_quarter : (now - 1.send(duration)).send(:"beginning_of_#{duration}")
58
58
  },
59
- ->(now) { now.send("beginning_of_#{duration}") }
59
+ ->(now) { now.send(:"beginning_of_#{duration}") }
60
60
  )
61
61
  end
62
62
 
63
63
  def self.previous_interval_to_date(duration)
64
64
  interval(
65
- ->(now) { now.send("beginning_of_#{duration}") },
65
+ ->(now) { now.send(:"beginning_of_#{duration}") },
66
66
  ->(now) { now }
67
67
  )
68
68
  end
@@ -61,7 +61,7 @@ module ForestAdminDatasourceToolkit
61
61
  if relation.is_a?(OneToManySchema)
62
62
  origin_tree = Nodes::ConditionTreeLeaf.new(relation.origin_key, Operators::EQUAL, origin_value)
63
63
  else
64
- through_collection = collection.datasource.collection(relation.through_collection)
64
+ through_collection = collection.datasource.get_collection(relation.through_collection)
65
65
  through_tree = ConditionTreeFactory.intersect([
66
66
  Nodes::ConditionTreeLeaf.new(relation.origin_key, Operators::EQUAL, origin_value),
67
67
  Nodes::ConditionTreeLeaf.new(relation.foreign_key, Operators::PRESENT)
@@ -86,8 +86,8 @@ module ForestAdminDatasourceToolkit
86
86
  unit = unit.downcase
87
87
  start = "beginning_of_#{unit}"
88
88
  end_ = "end_of_#{unit}"
89
- start_period = Time.now.in_time_zone(timezone).send("prev_#{unit}").send(start)
90
- end_period = Time.now.in_time_zone(timezone).send("prev_#{unit}").send(end_)
89
+ start_period = Time.now.in_time_zone(timezone).send(:"prev_#{unit}").send(start)
90
+ end_period = Time.now.in_time_zone(timezone).send(:"prev_#{unit}").send(end_)
91
91
 
92
92
  get_previous_condition_tree(field, start_period.to_datetime, end_period.to_datetime)
93
93
  end
@@ -104,13 +104,13 @@ module ForestAdminDatasourceToolkit
104
104
  end
105
105
 
106
106
  def self.make_through_filter(collection, id, relation_name, caller, base_foreign_filter)
107
- relation = collection.fields[relation_name]
107
+ relation = collection.schema[:fields][relation_name]
108
108
  origin_value = Utils::Collection.get_value(collection, caller, id, relation.origin_key_target)
109
109
  foreign_relation = Utils::Collection.get_through_target(collection, relation_name)
110
110
 
111
111
  # Optimization for many to many when there is not search/segment (saves one query)
112
112
  if foreign_relation && base_foreign_filter.nestable?
113
- foreign_key = collection.datasource.collection(relation.through_collection).fields[relation.foreign_key]
113
+ foreign_key = collection.datasource.get_collection(relation.through_collection).schema[:fields][relation.foreign_key]
114
114
  base_through_filter = base_foreign_filter.nest(foreign_relation)
115
115
  condition_tree = ConditionTreeFactory.intersect(
116
116
  [
@@ -129,7 +129,7 @@ module ForestAdminDatasourceToolkit
129
129
 
130
130
  # Otherwise we have no choice but to call the target collection so that search and segment
131
131
  # are correctly apply, and then match ids in the though collection.
132
- target = collection.datasource.collection(relation.foreign_collection)
132
+ target = collection.datasource.get_collection(relation.foreign_collection)
133
133
  records = target.list(
134
134
  caller,
135
135
  make_foreign_filter(collection, id, relation_name, caller, base_foreign_filter),
@@ -9,8 +9,8 @@ module ForestAdminDatasourceToolkit
9
9
  end
10
10
 
11
11
  relations.each do |relation, projection|
12
- schema = collection.fields[relation]
13
- association = collection.datasource.collection(schema.foreign_collection)
12
+ schema = collection.schema[:fields][relation]
13
+ association = collection.datasource.get_collection(schema.foreign_collection)
14
14
  projection_with_pks = projection.with_pks(association).nest(prefix: relation)
15
15
 
16
16
  projection_with_pks.each { |field| push(field) unless include?(field) }
@@ -4,14 +4,14 @@ module ForestAdminDatasourceToolkit
4
4
  class ProjectionFactory
5
5
  include ForestAdminDatasourceToolkit::Utils
6
6
  def self.all(collection)
7
- projection_fields = collection.fields.reduce([]) do |memo, path|
7
+ projection_fields = collection.schema[:fields].reduce([]) do |memo, path|
8
8
  column_name = path[0]
9
9
  schema = path[1]
10
10
  memo += [column_name] if schema.type == 'Column'
11
11
 
12
12
  if schema.type == 'OneToOne' || schema.type == 'ManyToOne'
13
- relation = collection.datasource.collection(schema.foreign_collection)
14
- relation_columns = relation.fields
13
+ relation = collection.datasource.get_collection(schema.foreign_collection)
14
+ relation_columns = relation.schema[:fields]
15
15
  .select { |_column_name, relation_column| relation_column.type == 'Column' }
16
16
  .keys
17
17
  .map { |relation_column_name| "#{column_name}:#{relation_column_name}" }
@@ -8,7 +8,7 @@ module ForestAdminDatasourceToolkit
8
8
  @collections = {}
9
9
  end
10
10
 
11
- def collection(name)
11
+ def get_collection(name)
12
12
  raise Exceptions::ForestException, "Collection #{name} not found." unless @collections.key? name
13
13
 
14
14
  @collections[name]
@@ -0,0 +1,110 @@
1
+ module ForestAdminDatasourceToolkit
2
+ module Decorators
3
+ class CollectionDecorator < Collection
4
+ attr_reader :datasource, :child_collection, :last_schema
5
+
6
+ def initialize(child_collection, datasource)
7
+ super
8
+ @child_collection = child_collection
9
+ @datasource = datasource
10
+
11
+ # When the child collection invalidates its schema, we also invalidate ours.
12
+ # This is done like this, and not in the markSchemaAsDirty method, because we don't have
13
+ # a reference to parent collections from children.
14
+ return unless child_collection.is_a?(CollectionDecorator)
15
+
16
+ original_child_mark_schema_as_dirty = child_collection.mark_schema_as_dirty
17
+ child_collection.mark_schema_as_dirty = lambda {
18
+ # Call the original method (the child)
19
+ original_child_mark_schema_as_dirty.call(child_collection)
20
+
21
+ # Invalidate our schema (the parent)
22
+ mark_schema_as_dirty
23
+ }
24
+ end
25
+
26
+ def native_driver
27
+ # TODO
28
+ end
29
+
30
+ def schema
31
+ unless @last_schema
32
+ sub_schema = @child_collection.schema
33
+ @last_schema = refine_schema(sub_schema)
34
+ end
35
+
36
+ @last_schema
37
+ end
38
+
39
+ def name
40
+ @child_collection.name
41
+ end
42
+
43
+ def execute(caller, name, data, filter = nil)
44
+ refined_filter = refine_filter(caller, filter)
45
+
46
+ @child_collection.execute(caller, name, data, refined_filter)
47
+ end
48
+
49
+ def get_form(caller, name, data = nil, filter = nil, metas = nil)
50
+ refined_filter = refine_filter(caller, filter)
51
+
52
+ @child_collection.get_form(caller, name, data, refined_filter, metas)
53
+ end
54
+
55
+ def create(caller, data)
56
+ @child_collection.create(caller, data)
57
+ end
58
+
59
+ def list(caller, filter = nil, projection = nil)
60
+ refined_filter = refine_filter(caller, filter)
61
+
62
+ @child_collection.list(caller, refined_filter, projection)
63
+ end
64
+
65
+ def update(caller, filter, patch)
66
+ refined_filter = refine_filter(caller, filter)
67
+
68
+ @child_collection.update(caller, refined_filter, patch)
69
+ end
70
+
71
+ def delete(caller, filter)
72
+ refined_filter = refine_filter(caller, filter)
73
+
74
+ @child_collection.delete(caller, refined_filter)
75
+ end
76
+
77
+ def aggregate(caller, filter, aggregation, limit = nil)
78
+ refined_filter = refine_filter(caller, filter)
79
+
80
+ @child_collection.aggregate(caller, refined_filter, aggregation, limit)
81
+ end
82
+
83
+ def render_chart(caller, name, record_id)
84
+ @child_collection.render_chart(caller, name, record_id)
85
+ end
86
+
87
+ protected
88
+
89
+ def mark_schema_as_dirty
90
+ @last_schema = nil
91
+ end
92
+
93
+ def refine_filter(_caller, filter = nil)
94
+ filter
95
+ end
96
+
97
+ def refine_schema(sub_schema)
98
+ sub_schema
99
+ end
100
+
101
+ private
102
+
103
+ def push_customization(customization)
104
+ @stack.queue_customization(customization)
105
+
106
+ self
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,28 @@
1
+ module ForestAdminDatasourceToolkit
2
+ module Decorators
3
+ class DatasourceDecorator
4
+ def initialize(child_datasource, collection_decorator_class)
5
+ @child_datasource = child_datasource
6
+ @collection_decorator_class = collection_decorator_class
7
+ @decorators = {}
8
+ end
9
+
10
+ def collections
11
+ @child_datasource.collections.transform_values { |c| get_collection(c.name) }
12
+ end
13
+
14
+ def get_collection(name)
15
+ collection = @child_datasource.get_collection(name)
16
+ unless @decorators.key?(collection.name)
17
+ @decorators[collection.name] = @collection_decorator_class.new(collection, self)
18
+ end
19
+
20
+ @decorators[collection.name]
21
+ end
22
+
23
+ def render_chart(caller, name)
24
+ @child_datasource.render_chart(caller, name)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -7,10 +7,10 @@ module ForestAdminDatasourceToolkit
7
7
  include ForestAdminDatasourceToolkit::Exceptions
8
8
 
9
9
  def self.get_inverse_relation(collection, relation_name)
10
- relation_field = collection.fields[relation_name]
11
- foreign_collection = collection.datasource.collection(relation_field.foreign_collection)
10
+ relation_field = collection.schema[:fields][relation_name]
11
+ foreign_collection = collection.datasource.get_collection(relation_field.foreign_collection)
12
12
 
13
- inverse = foreign_collection.fields.select do |_name, field|
13
+ inverse = foreign_collection.schema[:fields].select do |_name, field|
14
14
  field.is_a?(RelationSchema) &&
15
15
  field.foreign_collection == collection.name &&
16
16
  (
@@ -50,7 +50,7 @@ module ForestAdminDatasourceToolkit
50
50
  end
51
51
 
52
52
  def self.get_field_schema(collection, field_name)
53
- fields = collection.fields
53
+ fields = collection.schema[:fields]
54
54
  unless field_name.include?(':')
55
55
  raise ForestException, "Column not found #{collection.name}.#{field_name}" unless fields.key?(field_name)
56
56
 
@@ -67,7 +67,7 @@ module ForestAdminDatasourceToolkit
67
67
  end
68
68
 
69
69
  get_field_schema(
70
- collection.datasource.collection(relation_schema.foreign_collection), field_name.split(':')[1..].join(':')
70
+ collection.datasource.get_collection(relation_schema.foreign_collection), field_name.split(':')[1..].join(':')
71
71
  )
72
72
  end
73
73
 
@@ -90,11 +90,11 @@ module ForestAdminDatasourceToolkit
90
90
  end
91
91
 
92
92
  def self.get_through_target(collection, relation_name)
93
- relation = collection.fields[relation_name]
93
+ relation = collection.schema[:fields][relation_name]
94
94
  raise ForestException, 'Relation must be many to many' unless relation.is_a?(ManyToManySchema)
95
95
 
96
- through_collection = collection.datasource.collection(relation.through_collection)
97
- through_collection.fields.select do |field_name, field|
96
+ through_collection = collection.datasource.get_collection(relation.through_collection)
97
+ through_collection.schema[:fields].select do |field_name, field|
98
98
  if field.is_a?(ManyToOneSchema) &&
99
99
  field.foreign_collection == relation.foreign_collection &&
100
100
  field.foreign_key == relation.foreign_key &&
@@ -107,11 +107,11 @@ module ForestAdminDatasourceToolkit
107
107
  end
108
108
 
109
109
  def self.get_through_origin(collection, relation_name)
110
- relation = collection.fields[relation_name]
110
+ relation = collection.schema[:fields][relation_name]
111
111
  raise ForestException, 'Relation must be many to many' unless relation.is_a?(ManyToManySchema)
112
112
 
113
- through_collection = collection.datasource.collection(relation.through_collection)
114
- through_collection.fields.select do |field_name, field|
113
+ through_collection = collection.datasource.get_collection(relation.through_collection)
114
+ through_collection.schema[:fields].select do |field_name, field|
115
115
  if field.is_a?(ManyToOneSchema) &&
116
116
  field.foreign_collection == collection.name &&
117
117
  field.foreign_key == relation.origin_key &&
@@ -124,14 +124,14 @@ module ForestAdminDatasourceToolkit
124
124
  end
125
125
 
126
126
  def self.list_relation(collection, id, relation_name, caller, foreign_filter, projection)
127
- relation = collection.fields[relation_name]
128
- foreign_collection = collection.datasource.collection(relation.foreign_collection)
127
+ relation = collection.schema[:fields][relation_name]
128
+ foreign_collection = collection.datasource.get_collection(relation.foreign_collection)
129
129
 
130
130
  if relation.is_a?(ManyToManySchema) && foreign_filter.nestable?
131
131
  foreign_relation = get_through_target(collection, relation_name)
132
132
 
133
133
  if foreign_relation
134
- through_collection = collection.datasource.collection(relation.through_collection)
134
+ through_collection = collection.datasource.get_collection(relation.through_collection)
135
135
  records = through_collection.list(
136
136
  caller,
137
137
  FilterFactory.make_through_filter(collection, id, relation_name, caller, foreign_filter),
@@ -150,13 +150,13 @@ module ForestAdminDatasourceToolkit
150
150
  end
151
151
 
152
152
  def self.aggregate_relation(collection, id, relation_name, caller, foreign_filter, aggregation, limit = nil)
153
- relation = collection.fields[relation_name]
154
- foreign_collection = collection.datasource.collection(relation.foreign_collection)
153
+ relation = collection.schema[:fields][relation_name]
154
+ foreign_collection = collection.datasource.get_collection(relation.foreign_collection)
155
155
 
156
156
  if relation.is_a?(ManyToManySchema) && foreign_filter.nestable?
157
157
  foreign_relation = get_through_target(collection, relation_name)
158
158
  if foreign_relation
159
- through_collection = collection.datasource.collection(relation.through_collection)
159
+ through_collection = collection.datasource.get_collection(relation.through_collection)
160
160
 
161
161
  return through_collection.aggregate(
162
162
  caller,
@@ -2,33 +2,33 @@ module ForestAdminDatasourceToolkit
2
2
  module Utils
3
3
  class Schema
4
4
  def self.foreign_key?(collection, name)
5
- field = collection.fields[name]
5
+ field = collection.schema[:fields][name]
6
6
 
7
7
  field.type == 'Column' &&
8
- collection.fields.any? do |_key, relation|
8
+ collection.schema[:fields].any? do |_key, relation|
9
9
  relation.type == 'ManyToOne' && relation.foreign_key == name
10
10
  end
11
11
  end
12
12
 
13
13
  def self.primary_key?(collection, name)
14
- field = collection.fields[name]
14
+ field = collection.schema[:fields][name]
15
15
 
16
16
  field.type == 'Column' && field.is_primary_key
17
17
  end
18
18
 
19
19
  def self.primary_keys(collection)
20
- collection.fields.keys.select do |field_name|
21
- field = collection.fields[field_name]
20
+ collection.schema[:fields].keys.select do |field_name|
21
+ field = collection.schema[:fields][field_name]
22
22
  field.type == 'Column' && field.is_primary_key
23
23
  end
24
24
  end
25
25
 
26
26
  def self.get_to_many_relation(collection, relation_name)
27
- unless collection.fields.key?(relation_name)
27
+ unless collection.schema[:fields].key?(relation_name)
28
28
  raise Exceptions::ForestException, "Relation #{relation_name} not found"
29
29
  end
30
30
 
31
- relation = collection.fields[relation_name]
31
+ relation = collection.schema[:fields][relation_name]
32
32
 
33
33
  if relation.type != 'OneToMany' && relation.type != 'ManyToMany'
34
34
  raise Exceptions::ForestException,
@@ -1,3 +1,3 @@
1
1
  module ForestAdminDatasourceToolkit
2
- VERSION = "1.0.0-beta.23"
2
+ VERSION = "1.0.0-beta.24"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_datasource_toolkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.beta.23
4
+ version: 1.0.0.pre.beta.24
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: 2023-12-13 00:00:00.000000000 Z
12
+ date: 2023-12-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -82,6 +82,8 @@ files:
82
82
  - lib/forest_admin_datasource_toolkit/components/query/projection.rb
83
83
  - lib/forest_admin_datasource_toolkit/components/query/projection_factory.rb
84
84
  - lib/forest_admin_datasource_toolkit/datasource.rb
85
+ - lib/forest_admin_datasource_toolkit/decorators/collection_decorator.rb
86
+ - lib/forest_admin_datasource_toolkit/decorators/datasource_decorator.rb
85
87
  - lib/forest_admin_datasource_toolkit/exceptions/forest_exception.rb
86
88
  - lib/forest_admin_datasource_toolkit/schema/column_schema.rb
87
89
  - lib/forest_admin_datasource_toolkit/schema/primitive_type.rb