klastera 1.4.0.3 → 1.4.4.1

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: 8d11790c4adc1c5453272730dce9ca59a760bf5a6efcb57d6eefb974cd304aa3
4
- data.tar.gz: a42a54a74634773884f315eda227c42bf34999bf3b9fbeb82c826ce87dd872e2
3
+ metadata.gz: ef0519c775285f8e1684e2b7710f6a2729d89335f4742a04f4267a156870746d
4
+ data.tar.gz: 87adbf443e12d8dc8eb93a6d40dd7518d138dea65c404fc8ac19e9a69ea7a742
5
5
  SHA512:
6
- metadata.gz: 7c037938caa55966f240959944bec48e155525fedd23f15fa32e8711eb90121247498abe16b57882a9ac2db7e673761f711e377befe921cfe1f0d4018ededc85
7
- data.tar.gz: 3f6bab84a0d94a87362cd08ef68f546ddaba9aba1e6c02ce5108f625f91a166058cb9a103a938beb00643a186780ea7006ce6da25b218f3de4ceddbe229dd318
6
+ metadata.gz: 252b2cc54c25a5d1338d7064610ff2806c4e246f44f1101809fe97b5d0167e9d75de71994f1820e67f0e9c26e164be36ea2fd6ee0922eea9c8152c4ebbce83bb
7
+ data.tar.gz: 573ef0536c76d2fb6b199ac188cc90ec8f04b780f4d2562a6772b3f73051e77f62d4897ecc633fd3b869ae5d4c5f97a536bb31ebcf13a1c8c58904a37d326d4c
@@ -8,5 +8,11 @@ module Klastera::Concerns::ClusterEntity
8
8
  end
9
9
 
10
10
  module ClassMethods
11
+ def left_join_sources_of(scope_klass)
12
+ scope_klass_arel_table = scope_klass.arel_table
13
+ scope_klass_arel_table.join(arel_table, Arel::Nodes::OuterJoin).on(
14
+ scope_klass_arel_table[:id].eq(arel_table[:entity_id]), arel_table[:entity_type].eq(scope_klass.name)
15
+ ).join_sources
16
+ end
11
17
  end
12
18
  end
@@ -1,13 +1,16 @@
1
1
  module Klastera::Concerns::Clusterizable
2
2
  extend ActiveSupport::Concern
3
+
3
4
  included do
5
+ class MutipleClustersOperationError < StandardError; end
6
+
4
7
  belongs_to :cluster
5
8
 
6
9
  has_many :cluster_entities, as: :entity, class_name: Klastera::ClusterEntity
7
10
  accepts_nested_attributes_for :cluster_entities, reject_if: :all_blank, allow_destroy: true
8
11
 
9
- validates :cluster_id, presence: true, if: proc { self.try(:cluster_id) && self.organization.required_suborganization_mode? }
10
- validate :at_least_one_cluster_entity, if: proc { self.organization.required_suborganization_mode? }
12
+ validates :cluster_id, presence: true, if: -> { cluster_id.present? && organization.present? && organization.required_suborganization_mode? }
13
+ validate :at_least_one_cluster_entity, if: -> { organization.present? && organization.required_suborganization_mode? }
11
14
  validate :uniqueness_of_cluster_entity_record
12
15
 
13
16
  scope :includes_cluster, -> { includes(cluster_entities: :cluster) }
@@ -18,6 +21,10 @@ module Klastera::Concerns::Clusterizable
18
21
  end
19
22
  end
20
23
 
24
+ def allow_multiple_clusters?(default=:one)
25
+ organization.present? && organization.cluster_cardinality_of(self.class, default: default) == :many
26
+ end
27
+
21
28
  ##
22
29
  # This is a legacy method and we don't recommend using it.
23
30
  # Implement directly Klastera.entity_clusters_string_list instead of this method.
@@ -25,7 +32,7 @@ module Klastera::Concerns::Clusterizable
25
32
  ##
26
33
  def clusters_string_separated_by(separator,attribute=:name)
27
34
  Klastera.entity_clusters_string_list!(
28
- self.cluster_entities, separator, attribute
35
+ cluster_entities, separator, attribute
29
36
  )
30
37
  end
31
38
 
@@ -1,7 +1,7 @@
1
1
  module Klastera::Concerns::Organization
2
2
  extend ActiveSupport::Concern
3
3
  included do
4
-
4
+ serialize :cluster_config
5
5
  has_many :clusters
6
6
 
7
7
  validates :use_cluster_as, inclusion: { in: ::Cluster::MODES.map{|m|m.to_s}, message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ use_cluster_as.present? }
@@ -11,6 +11,17 @@ module Klastera::Concerns::Organization
11
11
  self.use_cluster_as.to_s.to_sym
12
12
  end
13
13
 
14
+ def cluster_cardinality_of(entity, default: :many)
15
+ if cluster_config.is_a?(Hash)
16
+ entities_cardinality = cluster_config[:entities]&.[](:cardinality)||{}
17
+ entity = entity.to_s.to_sym
18
+ if entities_cardinality.has_key?(entity)
19
+ default = entities_cardinality[entity]
20
+ end
21
+ end
22
+ default.to_s.to_sym
23
+ end
24
+
14
25
  ##
15
26
  # Return a boolean if one of three of options was set in organization
16
27
  # As useless option you can retrieve the value passing false as argument.
@@ -11,29 +11,29 @@ module Klastera::Concerns::User
11
11
 
12
12
  has_many :cluster_users, inverse_of: :user, class_name: ::ClusterUser.to_s
13
13
  accepts_nested_attributes_for :cluster_users, reject_if: :all_blank, allow_destroy: true
14
- validates :cluster_role, presence: true, if: proc{ self.organization.is_in_cluster_mode? }
15
- validates :cluster_role, inclusion: { in: CLUSTER_ROLES , message: I18n.t('klastera.clusters.wrong_option') }, if: proc{ cluster_role.present? }
16
- validate :at_least_one_role, if: proc{ self.use_cluster? && self.try(:need_cluster_assignation?) }
14
+ validates :cluster_role, presence: true, if: -> { organization.present? && organization.is_in_cluster_mode? }
15
+ validates :cluster_role, inclusion: { in: CLUSTER_ROLES , message: I18n.t('klastera.clusters.wrong_option') }, if: -> { cluster_role.present? }
16
+ validate :at_least_one_role, if: -> { use_cluster? && try(:need_cluster_assignation?) }
17
17
 
18
- def use_cluster?; self.cluster_role.present?; end
18
+ def use_cluster?; cluster_role.present?; end
19
19
 
20
- def is_a_cluster_root?; self.cluster_role == CLUSTER_ROOT; end
21
- def is_a_cluster_admin?; self.cluster_role == CLUSTER_ADMIN; end
22
- def is_a_cluster_user?; self.cluster_role == CLUSTER_USER; end
20
+ def is_a_cluster_root?; cluster_role == CLUSTER_ROOT; end
21
+ def is_a_cluster_admin?; cluster_role == CLUSTER_ADMIN; end
22
+ def is_a_cluster_user?; cluster_role == CLUSTER_USER; end
23
23
 
24
24
  def need_cluster_assignation?
25
- self.try(:organization).try(:required_suborganization_mode?) && self.is_a_cluster_user?
25
+ organization.present? && organization.required_suborganization_mode? && is_a_cluster_user?
26
26
  end
27
27
 
28
28
  def can_admin_clusters?
29
- self.organization.is_in_cluster_mode? && ( self.is_a_cluster_admin? || self.is_a_cluster_root? )
29
+ organization.present? && organization.is_in_cluster_mode? && ( is_a_cluster_admin? || is_a_cluster_root? )
30
30
  end
31
31
 
32
32
  #
33
33
  # It tells if this user should see what they cluster role or organization dictates
34
34
  # Adminers and users from show cluster modes skip cluster clause
35
35
  def cannot_skip_cluster_clause?
36
- ! ( self.is_a_cluster_admin? || self.is_a_cluster_root? || ( self.organization.optional_suborganization_mode? && self.cluster_users.blank? ) )
36
+ ! ( is_a_cluster_admin? || is_a_cluster_root? || ( organization.present? && organization.optional_suborganization_mode? && cluster_users.blank? ) )
37
37
  end
38
38
 
39
39
  #
@@ -43,9 +43,9 @@ module Klastera::Concerns::User
43
43
  # cluster_id is present (on show/use mode organizations).
44
44
  #
45
45
  def try_to_clusterify!(role,cluster_ids)
46
- if self.try(:organization).try(:is_in_cluster_mode?)
46
+ if organization.present? && organization.is_in_cluster_mode?
47
47
  self.cluster_role = role
48
- if self.try(:organization).try(:required_suborganization_mode?) || cluster_ids.present?
48
+ if ( organization.present? && organization.required_suborganization_mode? ) || cluster_ids.present?
49
49
  timestamp = DateTime.now.to_i
50
50
  nested_attributes = {}
51
51
  cluster_ids.each do |cluster_id|
@@ -0,0 +1,5 @@
1
+ class AddClusterConfigToOrganization < ActiveRecord::Migration
2
+ def change
3
+ add_column :organizations, :cluster_config, :text
4
+ end
5
+ end
@@ -7,7 +7,7 @@ module Klastera
7
7
 
8
8
  UNCLUSTERED_POSITION = 9999
9
9
  UNCLUSTERED_ENTITY = 'without_cluster'.freeze
10
- KLSTR_HELPERS = %i[ cluster_user cluster_organization cluster_list cluster_scope cluster_scope_through_of user_clusters_string_list ].freeze
10
+ KLSTR_HELPERS = %i[ cluster_user cluster_organization cluster_list cluster_scope cluster_scope_through_of user_clusters_string_list cluster_scope_left_join ].freeze
11
11
 
12
12
  class << self
13
13
 
@@ -79,9 +79,8 @@ module Klastera
79
79
  # cluster_filter_id is present when the optional_suborganization mode is on. BUT!
80
80
  # Be aware that if the cluster_filter is not present, the value of force_cluster_clause
81
81
  # will be overridden by the returned value of cannot_skip_cluster_clause? method.
82
- #
83
- def cluster_scope!(scope_klass, user, organization, cluster_filter=nil, force_cluster_clause=false)
84
- scope_klass = scope_class(scope_klass)
82
+ def should_clusterize_scope?(user, organization, cluster_filter=nil, force_cluster_clause=false)
83
+ should = false # I don't know if this is a good idea
85
84
  if organization.is_in_cluster_mode? && ( cluster_filter.present? || force_cluster_clause = user.cannot_skip_cluster_clause? ) # yes, this is an assignation
86
85
  cluster_ids = []
87
86
  # Set another variable as array to get the cluster id(s)
@@ -92,15 +91,27 @@ module Klastera
92
91
  end
93
92
  # We will avoid the query unless cluster_ids is having values OR force_cluster_clause is set (see method description)
94
93
  if cluster_ids.present? || force_cluster_clause
95
- scope_klass = scope_klass.eager_load(:organization,cluster_entities: :cluster)
96
94
  # We add the unclustered if the value of cluster_filter have the special without_cluster string or as method description says
97
95
  if cluster_ids.delete(UNCLUSTERED_ENTITY) || ( force_cluster_clause && organization.optional_suborganization_mode? )
98
96
  cluster_ids << nil
99
97
  end
100
- scope_klass = scope_klass.where( cluster_entities: { cluster_id: cluster_ids } )
98
+ should = true
101
99
  end
102
100
  end
103
- scope_klass.where(organization_id: organization)
101
+ yield(should,cluster_ids)
102
+ end
103
+
104
+ #
105
+ # The cleanest and fast way to clusterize a entity!
106
+ #
107
+ def cluster_scope!(scope_klass, user, organization, cluster_filter=nil, force_cluster_clause=false)
108
+ scope = scope_class(scope_klass)
109
+ should_clusterize_scope?(user,organization,cluster_filter,force_cluster_clause) do |should,cluster_ids|
110
+ if should
111
+ scope = scope.eager_load(:organization,cluster_entities: :cluster).where( cluster_entities: { cluster_id: cluster_ids } )
112
+ end
113
+ end
114
+ scope.where(organization_id: organization)
104
115
  end
105
116
 
106
117
 
@@ -110,7 +121,7 @@ module Klastera
110
121
  unclusterized_scope = scope_class(scope_klass)
111
122
 
112
123
  if organization.is_in_cluster_mode? && ( force_cluster_clause || user.cannot_skip_cluster_clause? )
113
- unclusterized_scope = unclusterized_scope.joins(relation => :cluster_entities)
124
+ unclusterized_scope = unclusterized_scope.joins(relation).joins(Klastera::ClusterEntity.left_join_sources_of(cluster_entity_klass))
114
125
  end
115
126
 
116
127
  if scope_klass.respond_to?(:organization)
@@ -152,6 +163,20 @@ module Klastera
152
163
 
153
164
  [ kluster_scope, grouped_cluster_scope ]
154
165
  end
166
+
167
+ #
168
+ # A helper that returns a CLUSTER SCOPE to build queries that need explicit LEFT OUTER JOIN clause,
169
+ # instead of the default INNER JOIN provide by ActiveRecord's joins method
170
+ #
171
+ def cluster_scope_left_join!(scope_klass,organization)
172
+ cluster_entities_arel_table = Klastera::ClusterEntity.arel_table
173
+ cluster_arel_table = ::Cluster.arel_table
174
+ cluster_entities_cluster = cluster_entities_arel_table.join(cluster_arel_table, Arel::Nodes::OuterJoin).on(
175
+ cluster_entities_arel_table[:cluster_id].eq(cluster_arel_table[:id]),
176
+ ).join_sources
177
+
178
+ scope_class(scope_klass).where(organization_id: organization).joins(Klastera::ClusterEntity.left_join_sources_of(scope_klass)).joins(cluster_entities_cluster)
179
+ end
155
180
  end
156
181
 
157
182
  ##################################################################################################################################################
@@ -193,6 +218,10 @@ module Klastera
193
218
  Klastera.user_clusters_string_list!(cluster_user, cluster_organization, object_entity.try(:cluster_entities), separator, attribute)
194
219
  end
195
220
 
221
+ def cluster_scope_left_join(scope_klass)
222
+ Klastera.cluster_scope_left_join!(scope_klas,cluster_organization)
223
+ end
224
+
196
225
  included do
197
226
  Klastera::KLSTR_HELPERS.each do |action|
198
227
  if respond_to?(:helper_method)
@@ -1,3 +1,3 @@
1
1
  module Klastera
2
- VERSION = "1.4.0.3"
2
+ VERSION = "1.4.4.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klastera
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0.3
4
+ version: 1.4.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gino Barahona
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-03 00:00:00.000000000 Z
11
+ date: 2020-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -93,6 +93,7 @@ files:
93
93
  - db/migrate/20200330010551_create_klastera_cluster_users.rb
94
94
  - db/migrate/20200330221601_add_order_field_to_clusters.rb
95
95
  - db/migrate/20200518142609_create_klastera_cluster_entities.rb
96
+ - db/migrate/20200908180057_add_cluster_config_to_organization.rb
96
97
  - lib/klastera.rb
97
98
  - lib/klastera/engine.rb
98
99
  - lib/klastera/version.rb