forest_admin_datasource_active_record 1.0.0.pre.beta.60 → 1.0.0.pre.beta.62

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: 06eb4e50d70ed020e78c247129d24f1a514efcc8e3150864ac00e2a420d715ed
4
- data.tar.gz: e11b2afab09fbf5ac3e9555a288f70638e2c01e5d2135a983b8601324d701916
3
+ metadata.gz: 768aba915cd8fc48929a8bdc08fdf81dd735aa9b6d8d7f2a7f2ecb4c99c4e854
4
+ data.tar.gz: 32a0e8e3b7468dd6ec2244ea1b59da6383af8f36f48b4c5d7025094550612eca
5
5
  SHA512:
6
- metadata.gz: 895ce913914b2400d39f09b197ef29e25524bcd524e75749a206cb5be6797665f026eac1ab0f99bceff4b11d9546c56edd3e92155c90a68434705faba6b411ec
7
- data.tar.gz: 5afa4e3d45800cce7d9f1a274eba8ccaf78d5c473460e1ccc56dada1064319d7e5d4b1a81b53ccadf293a64f61a1d607021665c6fdee7d95f1f143af4051d29f
6
+ metadata.gz: 7cea2e22bccfce7e48423cce3656b9457cea8882721bb6f39dc6ca44b7edc8fefcb9f0b8bde0226f33fa3ae5dcaae0b5d23113eeb92e6ef9e71793d70c427fb1
7
+ data.tar.gz: 7a015c989b6183d4a97c8d95f1f614b7a6fa58d64e2a498072e246218e6398040e22ec7098bc260ee8cc045119adf8155a64063cad007ad5f0c8ee93869979e6
@@ -6,9 +6,10 @@ module ForestAdminDatasourceActiveRecord
6
6
 
7
7
  attr_reader :model
8
8
 
9
- def initialize(datasource, model)
9
+ def initialize(datasource, model, support_polymorphic_relations: false)
10
10
  @model = model
11
- name = model.name.demodulize.underscore
11
+ @support_polymorphic_relations = support_polymorphic_relations
12
+ name = format_model_name(@model.name)
12
13
  super(datasource, name)
13
14
  fetch_fields
14
15
  fetch_associations
@@ -30,12 +31,12 @@ module ForestAdminDatasourceActiveRecord
30
31
  end
31
32
 
32
33
  def create(_caller, data)
33
- Utils::ActiveRecordSerializer.new(@model.create(data)).to_hash
34
+ Utils::ActiveRecordSerializer.new(@model.create(data)).to_hash(ProjectionFactory.all(self))
34
35
  end
35
36
 
36
37
  def update(_caller, filter, data)
37
38
  entity = Utils::Query.new(self, nil, filter).build.first
38
- entity.update(data)
39
+ entity&.update(data)
39
40
  end
40
41
 
41
42
  def delete(_caller, filter)
@@ -45,6 +46,10 @@ module ForestAdminDatasourceActiveRecord
45
46
 
46
47
  private
47
48
 
49
+ def format_model_name(class_name)
50
+ class_name.gsub('::', '__')
51
+ end
52
+
48
53
  def fetch_fields
49
54
  @model.columns_hash.each do |column_name, column|
50
55
  field = ForestAdminDatasourceToolkit::Schema::ColumnSchema.new(
@@ -63,49 +68,112 @@ module ForestAdminDatasourceActiveRecord
63
68
  end
64
69
  end
65
70
 
71
+ def association_primary_key?(association)
72
+ !association.association_primary_key.empty?
73
+ rescue StandardError
74
+ association.polymorphic?
75
+ end
76
+
66
77
  def fetch_associations
67
- associations(@model).each do |association|
78
+ associations(@model, support_polymorphic_relations: @support_polymorphic_relations).each do |association|
68
79
  case association.macro
69
80
  when :has_one
70
- add_field(
71
- association.name.to_s,
72
- ForestAdminDatasourceToolkit::Schema::Relations::OneToOneSchema.new(
73
- foreign_collection: association.class_name.demodulize.underscore,
74
- origin_key: association.foreign_key,
75
- origin_key_target: association.association_primary_key
76
- )
77
- )
81
+ if association_primary_key?(association)
82
+ if association.through_reflection?
83
+ add_field(
84
+ association.name.to_s,
85
+ ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
86
+ foreign_collection: format_model_name(association.klass.name),
87
+ origin_key: association.through_reflection.foreign_key,
88
+ origin_key_target: association.through_reflection.join_foreign_key,
89
+ foreign_key: association.join_foreign_key,
90
+ foreign_key_target: association.association_primary_key,
91
+ through_collection: format_model_name(association.through_reflection.klass.name)
92
+ )
93
+ )
94
+ elsif association.inverse_of.polymorphic?
95
+ add_field(
96
+ association.name.to_s,
97
+ ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicOneToOneSchema.new(
98
+ foreign_collection: format_model_name(association.klass.name),
99
+ origin_key: association.foreign_key,
100
+ origin_key_target: association.association_primary_key,
101
+ origin_type_field: association.inverse_of.foreign_type,
102
+ origin_type_value: @model.name
103
+ )
104
+ )
105
+ else
106
+ add_field(
107
+ association.name.to_s,
108
+ ForestAdminDatasourceToolkit::Schema::Relations::OneToOneSchema.new(
109
+ foreign_collection: format_model_name(association.klass.name),
110
+ origin_key: association.foreign_key,
111
+ origin_key_target: association.association_primary_key
112
+ )
113
+ )
114
+ end
115
+ end
78
116
  when :belongs_to
79
- add_field(
80
- association.name.to_s,
81
- ForestAdminDatasourceToolkit::Schema::Relations::ManyToOneSchema.new(
82
- foreign_collection: association.class_name.demodulize.underscore,
83
- foreign_key: association.foreign_key,
84
- foreign_key_target: association.association_primary_key
85
- )
86
- )
117
+ if association_primary_key?(association)
118
+ if polymorphic?(association)
119
+ foreign_collections = get_polymorphic_types(association)
120
+ add_field(
121
+ association.name.to_s,
122
+ ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicManyToOneSchema.new(
123
+ foreign_collections: foreign_collections.keys,
124
+ foreign_key: association.foreign_key,
125
+ foreign_key_type_field: association.foreign_type,
126
+ foreign_key_targets: foreign_collections
127
+ )
128
+ )
129
+ schema[:fields][association.foreign_key].is_read_only = true
130
+ schema[:fields][association.foreign_type].is_read_only = true
131
+ else
132
+ add_field(
133
+ association.name.to_s,
134
+ ForestAdminDatasourceToolkit::Schema::Relations::ManyToOneSchema.new(
135
+ foreign_collection: format_model_name(association.klass.name),
136
+ foreign_key: association.foreign_key,
137
+ foreign_key_target: association.association_primary_key
138
+ )
139
+ )
140
+ end
141
+ end
87
142
  when :has_many
88
- if association.through_reflection?
89
- add_field(
90
- association.name.to_s,
91
- ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
92
- foreign_collection: association.class_name.demodulize.underscore,
93
- origin_key: association.through_reflection.foreign_key,
94
- origin_key_target: association.through_reflection.join_foreign_key,
95
- foreign_key: association.join_foreign_key,
96
- foreign_key_target: association.association_primary_key,
97
- through_collection: association.through_reflection.class_name.demodulize.underscore
143
+ if association_primary_key?(association)
144
+ if association.through_reflection?
145
+ add_field(
146
+ association.name.to_s,
147
+ ForestAdminDatasourceToolkit::Schema::Relations::ManyToManySchema.new(
148
+ foreign_collection: format_model_name(association.klass.name),
149
+ origin_key: association.through_reflection.foreign_key,
150
+ origin_key_target: association.through_reflection.join_foreign_key,
151
+ foreign_key: association.join_foreign_key,
152
+ foreign_key_target: association.association_primary_key,
153
+ through_collection: format_model_name(association.through_reflection.klass.name)
154
+ )
155
+ )
156
+ elsif association.inverse_of.polymorphic?
157
+ add_field(
158
+ association.name.to_s,
159
+ ForestAdminDatasourceToolkit::Schema::Relations::PolymorphicOneToManySchema.new(
160
+ foreign_collection: format_model_name(association.klass.name),
161
+ origin_key: association.foreign_key,
162
+ origin_key_target: association.association_primary_key,
163
+ origin_type_field: association.inverse_of.foreign_type,
164
+ origin_type_value: @model.name
165
+ )
98
166
  )
99
- )
100
- else
101
- add_field(
102
- association.name.to_s,
103
- ForestAdminDatasourceToolkit::Schema::Relations::OneToManySchema.new(
104
- foreign_collection: association.class_name.demodulize.underscore,
105
- origin_key: association.foreign_key,
106
- origin_key_target: association.association_primary_key
167
+ else
168
+ add_field(
169
+ association.name.to_s,
170
+ ForestAdminDatasourceToolkit::Schema::Relations::OneToManySchema.new(
171
+ foreign_collection: format_model_name(association.klass.name),
172
+ origin_key: association.foreign_key,
173
+ origin_key_target: association.association_primary_key
174
+ )
107
175
  )
108
- )
176
+ end
109
177
  end
110
178
  end
111
179
  end
@@ -2,9 +2,12 @@ require 'active_record'
2
2
 
3
3
  module ForestAdminDatasourceActiveRecord
4
4
  class Datasource < ForestAdminDatasourceToolkit::Datasource
5
- def initialize(db_config = {})
5
+ attr_reader :models
6
+
7
+ def initialize(db_config = {}, support_polymorphic_relations: false)
6
8
  super()
7
9
  @models = []
10
+ @support_polymorphic_relations = support_polymorphic_relations
8
11
  @habtm_models = {}
9
12
  init_orm(db_config)
10
13
  generate
@@ -15,15 +18,26 @@ module ForestAdminDatasourceActiveRecord
15
18
  def generate
16
19
  ActiveRecord::Base.descendants.each { |model| fetch_model(model) }
17
20
  @models.each do |model|
18
- add_collection(Collection.new(self, model))
21
+ add_collection(
22
+ Collection.new(self, model, support_polymorphic_relations: @support_polymorphic_relations)
23
+ )
19
24
  end
20
25
  end
21
26
 
27
+ def primary_key?(model)
28
+ !model.primary_key.empty?
29
+ rescue StandardError
30
+ false
31
+ end
32
+
22
33
  def fetch_model(model)
23
34
  if model.name.start_with?('HABTM_')
24
35
  build_habtm(model)
25
36
  else
26
- @models << model unless model.abstract_class? || @models.include?(model) || !model.table_exists?
37
+ @models << model unless model.abstract_class? ||
38
+ @models.include?(model) ||
39
+ !model.table_exists? ||
40
+ !primary_key?(model)
27
41
  end
28
42
  end
29
43
 
@@ -1,14 +1,19 @@
1
1
  module ForestAdminDatasourceActiveRecord
2
2
  module Parser
3
3
  module Relation
4
- def associations(model)
4
+ def associations(model, support_polymorphic_relations: false)
5
5
  model.reflect_on_all_associations.select do |association|
6
- !polymorphic?(association) && !active_type?(association.klass)
6
+ if support_polymorphic_relations
7
+ polymorphic?(association) ? true : !active_type?(association.klass)
8
+ else
9
+ !polymorphic?(association) && !active_type?(association.klass)
10
+ end
7
11
  end
8
12
  end
9
13
 
10
14
  def polymorphic?(association)
11
- association.options[:polymorphic]
15
+ (association.options.key?(:polymorphic) && association.options[:polymorphic]) ||
16
+ association.inverse_of&.polymorphic?
12
17
  end
13
18
 
14
19
  # NOTICE: Ignores ActiveType::Object association during introspection and interactions.
@@ -16,6 +21,17 @@ module ForestAdminDatasourceActiveRecord
16
21
  def active_type?(model)
17
22
  Object.const_defined?('ActiveType::Object') && model < ActiveType::Object
18
23
  end
24
+
25
+ def get_polymorphic_types(relation)
26
+ types = {}
27
+ @datasource.models.each do |model|
28
+ unless model.reflect_on_all_associations.none? { |assoc| assoc.options[:as] == relation.name.to_sym }
29
+ types[format_model_name(model.name)] = model.primary_key
30
+ end
31
+ end
32
+
33
+ types
34
+ end
19
35
  end
20
36
  end
21
37
  end
@@ -13,7 +13,7 @@ module ForestAdminDatasourceActiveRecord
13
13
  hash.merge! object.attributes
14
14
 
15
15
  if with_associations
16
- each_association_collection(object) do |association_name, item|
16
+ each_association_collection(object, projection) do |association_name, item|
17
17
  hash[association_name] = hash_object(
18
18
  item,
19
19
  projection.relations[association_name],
@@ -25,9 +25,10 @@ module ForestAdminDatasourceActiveRecord
25
25
  hash
26
26
  end
27
27
 
28
- def each_association_collection(object)
28
+ def each_association_collection(object, projection)
29
29
  one_associations = %i[has_one belongs_to]
30
- object.class.reflect_on_all_associations.filter { |a| one_associations.include?(a.macro) }
30
+ object.class.reflect_on_all_associations
31
+ .filter { |a| one_associations.include?(a.macro) && projection.relations.key?(a.name.to_s) }
31
32
  .each { |association| yield(association.name.to_s, object.send(association.name.to_s)) }
32
33
  end
33
34
  end
@@ -123,14 +123,11 @@ module ForestAdminDatasourceActiveRecord
123
123
  end
124
124
 
125
125
  def format_field(field)
126
- @select << "#{@collection.model.table_name}.#{field}"
127
-
128
126
  if field.include?(':')
129
127
  relation_name, field = field.split(':')
130
128
  relation = @collection.schema[:fields][relation_name]
131
129
  table_name = @collection.datasource.get_collection(relation.foreign_collection).model.table_name
132
130
  add_join_relation(relation_name)
133
- @select << "#{table_name}.#{field}"
134
131
 
135
132
  return "#{table_name}.#{field}"
136
133
  end
@@ -1,3 +1,3 @@
1
1
  module ForestAdminDatasourceActiveRecord
2
- VERSION = "1.0.0-beta.60"
2
+ VERSION = "1.0.0-beta.62"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_datasource_active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.beta.60
4
+ version: 1.0.0.pre.beta.62
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: 2024-07-08 00:00:00.000000000 Z
12
+ date: 2024-08-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord