app/models/unidom/common/concerns/model_extension.rb in unidom-common-1.2 vs app/models/unidom/common/concerns/model_extension.rb in unidom-common-1.3

- old
+ new

@@ -1,186 +1,179 @@ -module Unidom - module Common - module Concerns +module Unidom::Common::Concerns::ModelExtension - module ModelExtension + extend ActiveSupport::Concern - extend ActiveSupport::Concern + included do |includer| - included do |includer| + validates :state, presence: true, length: { is: columns_hash['state'].limit } - validates :state, presence: true, length: { is: columns_hash['state'].limit } + scope :included_by, ->(inclusion) { where id: inclusion } + scope :excluded_by, ->(exclusion) { where.not id: exclusion } - scope :included_by, ->(inclusion) { where id: inclusion } - scope :excluded_by, ->(exclusion) { where.not id: exclusion } + scope :transited_to, ->(states) { where state: states } - scope :transited_to, ->(states) { where state: states } + scope :valid_at, ->(now: Time.now) { where "? BETWEEN #{includer.table_name}.opened_at AND #{includer.table_name}.closed_at", now } + scope :valid_duration, ->(range) { where "(#{includer.table_name}.opened_at BETWEEN ? AND ?) OR (#{includer.table_name}.closed_at <= ? AND #{includer.table_name}.closed_at >= ?)", range.min, range.max, range.max, range.min } - scope :valid_at, ->(now: Time.now) { where "? BETWEEN #{includer.table_name}.opened_at AND #{includer.table_name}.closed_at", now } - scope :valid_duration, ->(range) { where "(#{includer.table_name}.opened_at BETWEEN ? AND ?) OR (#{includer.table_name}.closed_at <= ? AND #{includer.table_name}.closed_at >= ?)", range.min, range.max, range.max, range.min } + scope :alive, ->(living: true) { where defunct: !living } + scope :dead, ->(defunct: true) { where defunct: defunct } - scope :alive, ->(living: true) { where defunct: !living } - scope :dead, ->(defunct: true) { where defunct: defunct } + scope :notation_column_where, ->(name, operator, value) do + operation = :like==operator ? { operator: 'ILIKE', value: "%#{value}%" } : { operator: operator.to_s, value: value } + where "#{table_name}.notation -> 'columns' ->> '#{name}' #{operation[:operator]} :value", value: operation[:value] + end - scope :notation_column_where, ->(name, operator, value) do - operation = :like==operator ? { operator: 'ILIKE', value: "%#{value}%" } : { operator: operator.to_s, value: value } - where "#{table_name}.notation -> 'columns' ->> '#{name}' #{operation[:operator]} :value", value: operation[:value] - end + scope :notation_boolean_column_where, ->(name, value) do + where "(#{table_name}.notation -> 'columns' ->> '#{name}')::boolean = :value", value: (value ? true : false) + end - scope :notation_boolean_column_where, ->(name, value) do - where "(#{table_name}.notation -> 'columns' ->> '#{name}')::boolean = :value", value: (value ? true : false) - end + if columns_hash['ordinal'].present?&&:integer==columns_hash['ordinal'].type + validates :ordinal, presence: true, numericality: { integer_only: true, greater_than: 0 } + scope :ordinal_is, ->(ordinal) { where ordinal: ordinal } + end - if columns_hash['ordinal'].present?&&:integer==columns_hash['ordinal'].type - validates :ordinal, presence: true, numericality: { integer_only: true, greater_than: 0 } - scope :ordinal_is, ->(ordinal) { where ordinal: ordinal } - end + if columns_hash['uuid'].present?&&:uuid==columns_hash['uuid'].type + validates :uuid, presence: true, length: { is: 36 } + scope :uuid_is, ->(uuid) { where uuid: uuid } + end - if columns_hash['uuid'].present?&&:uuid==columns_hash['uuid'].type - validates :uuid, presence: true, length: { is: 36 } - scope :uuid_is, ->(uuid) { where uuid: uuid } - end + if columns_hash['elemental'].present?&&:boolean==columns_hash['elemental'].type + scope :primary, ->(elemental = true) { where elemental: elemental } + end - if columns_hash['elemental'].present?&&:boolean==columns_hash['elemental'].type - scope :primary, ->(elemental = true) { where elemental: elemental } - end + if columns_hash['grade'].present?&&:integer==columns_hash['grade'].type + validates :grade, presence: true, numericality: { integer_only: true, greater_than_or_equal_to: 0 } + scope :grade_is, ->(grade) { where grade: grade } + scope :grade_higher_than, ->(grade) { where "grade > :grade", grade: grade } + scope :grade_lower_than, ->(grade) { where "grade < :grade", grade: grade } + end - if columns_hash['grade'].present?&&:integer==columns_hash['grade'].type - validates :grade, presence: true, numericality: { integer_only: true, greater_than_or_equal_to: 0 } - scope :grade_is, ->(grade) { where grade: grade } - scope :grade_higher_than, ->(grade) { where "grade > :grade", grade: grade } - scope :grade_lower_than, ->(grade) { where "grade < :grade", grade: grade } - end + if columns_hash['priority'].present?&&:integer==columns_hash['priority'].type + validates :priority, presence: true, numericality: { integer_only: true, greater_than_or_equal_to: 0 } + scope :priority_is, ->(priority) { where priority: priority } + scope :priority_higher_than, ->(priority) { where "priority > :priority", priority: priority } + scope :priority_lower_than, ->(priority) { where "priority < :priority", priority: priority } + end - if columns_hash['priority'].present?&&:integer==columns_hash['priority'].type - validates :priority, presence: true, numericality: { integer_only: true, greater_than_or_equal_to: 0 } - scope :priority_is, ->(priority) { where priority: priority } - scope :priority_higher_than, ->(priority) { where "priority > :priority", priority: priority } - scope :priority_lower_than, ->(priority) { where "priority < :priority", priority: priority } - end + if columns_hash['slug'].present?&&:string==columns_hash['slug'].type + validates :slug, presence: true, length: { in: 1..columns_hash['slug'].limit }, uniqueness: true + scope :slug_is, ->(slug) { where slug: slug } + before_validation -> { + prefix = build_slug.to_s[0..(self.class.columns_hash['slug'].limit-37)] + unique = prefix + while includer.slug_is(unique).count>0 + unique = "#{prefix}-#{::SecureRandom.uuid}" + end + self.slug = unique + }, on: :create + # on update: re-generate the slug if the slug was assigned to empty. + # to_query: escape characters + end - if columns_hash['slug'].present?&&:string==columns_hash['slug'].type - validates :slug, presence: true, length: { in: 1..columns_hash['slug'].limit }, uniqueness: true - scope :slug_is, ->(slug) { where slug: slug } - before_validation -> { - prefix = build_slug.to_s[0..(self.class.columns_hash['slug'].limit-37)] - unique = prefix - while includer.slug_is(unique).count>0 - unique = "#{prefix}-#{::SecureRandom.uuid}" - end - self.slug = unique - }, on: :create - # on update: re-generate the slug if the slug was assigned to empty. - # to_query: escape characters - end + columns_hash.each do |column_name, hash| - columns_hash.each do |column_name, hash| + name = column_name.to_s - name = column_name.to_s + if ('code'==name||name.ends_with?('_code'))&&:string==columns_hash[name].type + class_eval do + if columns_hash[name].null + validates name.to_sym, allow_blank: true, length: { maximum: columns_hash[name].limit } + scope "#{name}_length_is".to_sym, ->(length) { where "LENGTH(#{name}) = :length", length: length } + elsif columns_hash[name].limit<=4 + validates name.to_sym, presence: true, length: { is: columns_hash[name].limit } + else + validates name.to_sym, presence: true, length: { maximum: columns_hash[name].limit } + end + scope "#{name}d_as".to_sym, ->(code) { where name => code } + scope "not_#{name}d_as".to_sym, ->(code) { where.not name => code } + scope "#{name}_starting_with".to_sym, ->(prefix) { where "#{name} LIKE :prefix", prefix: "#{prefix}%" } + scope "#{name}_ending_with".to_sym, ->(suffix) { where "#{name} LIKE :suffix", suffix: "%#{suffix}" } + end + end - if ('code'==name||name.ends_with?('_code'))&&:string==columns_hash[name].type - class_eval do - if columns_hash[name].null - validates name.to_sym, allow_blank: true, length: { maximum: columns_hash[name].limit } - scope "#{name}_length_is".to_sym, ->(length) { where "LENGTH(#{name}) = :length", length: length } - elsif columns_hash[name].limit<=4 - validates name.to_sym, presence: true, length: { is: columns_hash[name].limit } - else - validates name.to_sym, presence: true, length: { maximum: columns_hash[name].limit } - end - scope "#{name}d_as".to_sym, ->(code) { where name => code } - scope "not_#{name}d_as".to_sym, ->(code) { where.not name => code } - scope "#{name}_starting_with".to_sym, ->(prefix) { where "#{name} LIKE :prefix", prefix: "#{prefix}%" } - scope "#{name}_ending_with".to_sym, ->(suffix) { where "#{name} LIKE :suffix", suffix: "%#{suffix}" } - end - end + if name.ends_with?('_at')&&:datetime==columns_hash[name].type + matched = /\A(.+)_at\z/.match name + class_eval do + scope :"#{matched[1]}_on", ->(date) { where name => date.beginning_of_day..date.end_of_day } + scope :"#{matched[1]}_during", ->(range) { where name => range } + scope :"#{matched[1]}_before", ->(time) { where "#{table_name}.#{name} < :time", time: time } + scope :"#{matched[1]}_not_after", ->(time) { where "#{table_name}.#{name} <= :time", time: time } + scope :"#{matched[1]}_after", ->(time) { where "#{table_name}.#{name} > :time", time: time } + scope :"#{matched[1]}_not_before", ->(time) { where "#{table_name}.#{name} >= :time", time: time } + end + end - if name.ends_with?('_at')&&:datetime==columns_hash[name].type - matched = /\A(.+)_at\z/.match name - class_eval do - scope :"#{matched[1]}_on", ->(date) { where name => date.beginning_of_day..date.end_of_day } - scope :"#{matched[1]}_during", ->(range) { where name => range } - scope :"#{matched[1]}_before", ->(time) { where "#{table_name}.#{name} < :time", time: time } - scope :"#{matched[1]}_not_after", ->(time) { where "#{table_name}.#{name} <= :time", time: time } - scope :"#{matched[1]}_after", ->(time) { where "#{table_name}.#{name} > :time", time: time } - scope :"#{matched[1]}_not_before", ->(time) { where "#{table_name}.#{name} >= :time", time: time } - end - end + if name.ends_with?('_state')&&:string==columns_hash[name].type + matched = /\A(.+)_state\z/.match name + class_eval do + validates name.to_sym, presence: true, length: { is: columns_hash[name].limit } + scope :"#{matched[1]}_transited_to", ->(states) { where name => states } + end + end - if name.ends_with?('_state')&&:string==columns_hash[name].type - matched = /\A(.+)_state\z/.match name - class_eval do - scope :"#{matched[1]}_transited_to", ->(states) { where name => states } - end - end + end - end + includer.define_singleton_method :default_scope do + includer.all.order("#{includer.table_name}.ordinal ASC") if includer.columns_hash['ordinal'].present? + includer.all.order("#{includer.table_name}.created_at ASC") + #relation = base.all + #scopes.each do |s| relation = relation.send s.to_sym end + #relation + end - includer.define_singleton_method :default_scope do - includer.all.order("#{includer.table_name}.ordinal ASC") if includer.columns_hash['ordinal'].present? - includer.all.order("#{includer.table_name}.created_at ASC") - #relation = base.all - #scopes.each do |s| relation = relation.send s.to_sym end - #relation - end + def soft_destroy + self.closed_at = Time.now + self.defunct = true + self.save + end - def soft_destroy - self.closed_at = Time.now - self.defunct = true - self.save - end + def build_slug + if respond_to? :name + name + elsif respond_to? :title + title + else + ::SecureRandom.uuid + end + end - def build_slug - if respond_to? :name - name - elsif respond_to? :title - title - else - ::SecureRandom.uuid - end - end + end - end + module ClassMethods - module ClassMethods + def to_id(model) + model.respond_to?(:id) ? model.id : model + end - def to_id(model) - model.respond_to?(:id) ? model.id : model + def notation_column(*names) + names.each do |name| + name = name.to_s + instance_eval do + define_method(name) do + notation.try(:[], 'columns').try(:[], name) end - - def notation_column(*names) - names.each do |name| - name = name.to_s - instance_eval do - define_method(name) do - notation.try(:[], 'columns').try(:[], name) - end - define_method("#{name}=") do |value| - notation['columns'] ||= {} - notation['columns'][name] = value - end - end - end + define_method("#{name}=") do |value| + notation['columns'] ||= {} + notation['columns'][name] = value end + end + end + end - def notation_boolean_column(*names) - names.each do |name| - name = name.to_s - instance_eval do - define_method("#{name}?") do - notation.try(:[], 'columns').try(:[], name) - end - define_method("#{name}=") do |value| - notation['columns'] ||= {} - notation['columns'][name] = value - end - end - end + def notation_boolean_column(*names) + names.each do |name| + name = name.to_s + instance_eval do + define_method("#{name}?") do + notation.try(:[], 'columns').try(:[], name) end - + define_method("#{name}=") do |value| + notation['columns'] ||= {} + notation['columns'][name] = value + end end - end - end + end -end \ No newline at end of file + +end