klastera 1.4.0.3 → 1.4.4.1

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: 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