Class: ForestAdminDatasourceToolkit::Utils::Collection

Inherits:
Object
  • Object
show all
Includes:
Components::Query, Exceptions, Schema, Schema::Relations
Defined in:
lib/forest_admin_datasource_toolkit/utils/collection.rb

Class Method Summary collapse

Class Method Details

.aggregate_relation(collection, primary_key_values, relation_name, caller, foreign_filter, aggregation, limit = nil) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 159

def self.aggregate_relation(collection, primary_key_values, relation_name, caller, foreign_filter, aggregation, limit = nil)
  relation = collection.schema[:fields][relation_name]
  foreign_collection = collection.datasource.get_collection(relation.foreign_collection)

  if relation.is_a?(ManyToManySchema) && foreign_filter.nestable?
    foreign_relation = get_through_target(collection, relation_name)
    if foreign_relation
      through_collection = collection.datasource.get_collection(relation.through_collection)

      return through_collection.aggregate(
        caller,
        FilterFactory.make_through_filter(collection, primary_key_values, relation_name, caller, foreign_filter),
        aggregation,
        limit
      )
    end
  end

  foreign_collection.aggregate(
    caller,
    FilterFactory.make_foreign_filter(collection, primary_key_values, relation_name, caller, foreign_filter),
    aggregation,
    limit
  )
end

.get_field_schema(collection, field_name) ⇒ Object

Raises:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 59

def self.get_field_schema(collection, field_name)
  fields = collection.schema[:fields]
  unless field_name.include?(':')
    raise ForestException, "Column not found #{collection.name}.#{field_name}" unless fields.key?(field_name)

    return fields[field_name]
  end

  association_name = field_name.split(':')[0]
  relation_schema = fields[association_name]

  raise ForestException, "Relation not found #{collection.name}.#{association_name}" unless relation_schema

  if relation_schema.type != 'ManyToOne' && relation_schema.type != 'OneToOne'
    raise ForestException, "Unexpected field type #{relation_schema.type}: #{collection.name}.#{association_name}"
  end

  get_field_schema(
    collection.datasource.get_collection(relation_schema.foreign_collection), field_name.split(':')[1..].join(':')
  )
end

.get_inverse_relation(collection, relation_name) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 9

def self.get_inverse_relation(collection, relation_name)
  relation_field = collection.schema[:fields][relation_name]
  foreign_collection = collection.datasource.get_collection(relation_field.foreign_collection)
  polymorphic_relations = %w[PolymorphicOneToOne PolymorphicOneToMany]

  inverse = foreign_collection.schema[:fields].select do |_name, field|
    if polymorphic_relations.include?(relation_field.type)
      field.is_a?(PolymorphicManyToOneSchema) &&
        field.foreign_key_type_field == relation_field.origin_type_field &&
        field.foreign_key == relation_field.origin_key &&
        field.foreign_collections.include?(collection.name)
    else
      field.is_a?(RelationSchema) &&
        field.foreign_collection == collection.name &&
        (
          (field.is_a?(ManyToManySchema) && relation_field.is_a?(ManyToManySchema) &&
            many_to_many_inverse?(field, relation_field)) ||
            (field.is_a?(ManyToOneSchema) &&
              (relation_field.is_a?(OneToOneSchema) || relation_field.is_a?(OneToManySchema)) &&
              many_to_one_inverse?(field, relation_field)) ||
            ((field.is_a?(OneToOneSchema) || field.is_a?(OneToManySchema)) &&
              relation_field.is_a?(ManyToOneSchema) && other_inverse?(field, relation_field))
        )
    end
  end.keys.first

  inverse || nil
end

.get_through_origin(collection, relation_name) ⇒ Object

Raises:



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 116

def self.get_through_origin(collection, relation_name)
  relation = collection.schema[:fields][relation_name]
  raise ForestException, 'Relation must be many to many' unless relation.is_a?(ManyToManySchema)

  through_collection = collection.datasource.get_collection(relation.through_collection)
  through_collection.schema[:fields].select do |field_name, field|
    if field.is_a?(ManyToOneSchema) &&
       field.foreign_collection == collection.name &&
       field.foreign_key == relation.origin_key &&
       field.foreign_key_target == relation.origin_key_target
      return field_name
    end
  end

  nil
end

.get_through_target(collection, relation_name) ⇒ Object

Raises:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 99

def self.get_through_target(collection, relation_name)
  relation = collection.schema[:fields][relation_name]
  raise ForestException, 'Relation must be many to many' unless relation.is_a?(ManyToManySchema)

  through_collection = collection.datasource.get_collection(relation.through_collection)
  through_collection.schema[:fields].select do |field_name, field|
    if field.is_a?(ManyToOneSchema) &&
       field.foreign_collection == relation.foreign_collection &&
       field.foreign_key == relation.foreign_key &&
       field.foreign_key_target == relation.foreign_key_target
      return field_name
    end
  end

  nil
end

.get_value(collection, caller, primary_key_values, field) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 81

def self.get_value(collection, caller, primary_key_values, field)
  if primary_key_values.is_a? Array
    index = Schema.primary_keys(collection).index(field)

    return primary_key_values[index] if index
  elsif Schema.primary_keys(collection).include?(field)
    return primary_key_values[field]
  end

  records = collection.list(
    caller,
    ForestAdminDatasourceToolkit::Components::Query::Filter.new(condition_tree: ConditionTree::ConditionTreeFactory.match_ids(collection, [primary_key_values])),
    Projection.new([field])
  )

  records.first&.[](field)
end

.list_relation(collection, primary_key_values, relation_name, caller, foreign_filter, projection) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 133

def self.list_relation(collection, primary_key_values, relation_name, caller, foreign_filter, projection)
  relation = collection.schema[:fields][relation_name]
  foreign_collection = collection.datasource.get_collection(relation.foreign_collection)

  if relation.is_a?(ManyToManySchema) && foreign_filter.nestable?
    foreign_relation = get_through_target(collection, relation_name)

    if foreign_relation
      through_collection = collection.datasource.get_collection(relation.through_collection)
      records = through_collection.list(
        caller,
        FilterFactory.make_through_filter(collection, primary_key_values, relation_name, caller, foreign_filter),
        projection.nest(prefix: foreign_relation)
      )

      return records.map { |r| r[foreign_relation] }
    end
  end

  foreign_collection.list(
    caller,
    FilterFactory.make_foreign_filter(collection, primary_key_values, relation_name, caller, foreign_filter),
    projection
  )
end

.many_to_many_inverse?(field, relation_field) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
41
42
43
44
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 38

def self.many_to_many_inverse?(field, relation_field)
  field.is_a?(ManyToManySchema) &&
    relation_field.is_a?(ManyToManySchema) &&
    field.origin_key == relation_field.foreign_key &&
    field.through_collection == relation_field.through_collection &&
    field.foreign_key == relation_field.origin_key
end

.many_to_one_inverse?(field, relation_field) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
49
50
51
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 46

def self.many_to_one_inverse?(field, relation_field)
  field.is_a?(ManyToOneSchema) &&
    (relation_field.is_a?(OneToManySchema) ||
      relation_field.is_a?(OneToOneSchema)) &&
    field.foreign_key == relation_field.origin_key
end

.other_inverse?(field, relation_field) ⇒ Boolean

Returns:

  • (Boolean)


53
54
55
56
57
# File 'lib/forest_admin_datasource_toolkit/utils/collection.rb', line 53

def self.other_inverse?(field, relation_field)
  (field.is_a?(OneToManySchema) || field.is_a?(OneToOneSchema)) &&
    relation_field.is_a?(ManyToOneSchema) &&
    field.origin_key == relation_field.foreign_key
end