# File lib/datoki.rb, line 865 def primary_key name, meta = self.class.fields.detect { |k, v| v[:primary_key] } fail "Primary key not found." unless meta meta end
module Datoki
Constants
- Actions
- Char_Types
- Invalid
- Key_Not_Found
- Numeric_Types
- Schema_Conflict
- Types
- UTC_NOW
- UTC_NOW_DATE
- UTC_NOW_RAW
Attributes
Public Class Methods
db(db = :return)
click to toggle source
# File lib/datoki.rb, line 29 def db db = :return return @db if db == :return @db = db @tables = @db.tables end
db_type_to_ruby(type, alt = nil)
click to toggle source
# File lib/datoki.rb, line 35 def db_type_to_ruby type, alt = nil if Datoki::Types.include?( type.to_sym ) type.to_sym elsif type['character varying'] :varchar elsif Datoki::Types.include?(alt) alt else fail("Unknown db type: #{type.inspect}") end end
included(klass)
click to toggle source
# File lib/datoki.rb, line 24 def included klass klass.extend Def_Field klass.initialize_def_field end
new(unknown = nil)
click to toggle source
# File lib/datoki.rb, line 507 def initialize unknown = nil @data = nil @field_name = nil @clean = nil @error = nil @skips = {} @db_ops = {} # Ex: :db_insert=>true, :db_update=>true if unknown is_record = unknown.keys.all? { |f| self.class.fields.has_key?(f) || (self.class.schema && self.class.schema.has_key?(f)) } if is_record @data = unknown @data.default_proc = Key_Not_Found else @raw = unknown end end if @raw schema = self.class.schema case when create? create when update? clean primary_key[:name] update when delete? delete end if @clean @clean.each { |k, v| # === Delete nil value if schema has a default value: @clean.delete(k) if @clean[k].nil? && schema[k] && schema[k][:default] } end fail "No clean values found." if (!@clean || @clean.empty?) if !@skips[:db] && !self.class.schema.empty? begin case when create? db_insert when update? db_update when delete? final = db_clean DB[self.class.table]. where(primary_key[:name] => final.delete(primary_key[:name])). delete end rescue Sequel::UniqueConstraintViolation => e self.class.fields.each { |f, meta| if meta[:unique_index] && e.message[%^unique constraint "#{meta[:unique_index]}"^] field_name f fail! :unique, "{{English name}} already taken: #{meta[:name]}" end } raise e end # === begin/rescue end # === if !@skips[:db] end # === if @raw end
Public Instance Methods
TABLE()
click to toggle source
# File lib/datoki.rb, line 891 def TABLE self.class::TABLE end
clean(*args)
click to toggle source
# File lib/datoki.rb, line 617 def clean *args @clean ||= {} return @clean if args.empty? # === Handle required fields: # Example: # :name!, :age! if args.size > 1 return args.each { |f| clean f } end name = args.first if (real_name = self.class.fields_as_required[name]) return(clean! real_name) end @clean[name] = @raw[name] if !clean.has_key?(name) && @raw.has_key?(name) # === Skip cleaning if key is not set: return nil unless @clean.has_key?(name) field_name(name) f_meta = self.class.fields[name] # === Strip the value: if clean[name].is_a?(String) && field[:allow][:strip] clean[name].strip! end if field?(:chars) && !field.has_key?(:min) && clean[name].is_a?(String) && field[:allow][:null] clean[name] = nil end if field?(:numeric) && clean[name].is_a?(String) clean_val = Integer(clean[name]) rescue String if clean_val == String fail! :wrong_type, "{{English name}} must be numeric." else clean[name] = clean_val end end if field?(:text) && clean[name].is_a?(String) && clean[name].empty? && field[:min].to_i > 0 fail! :required, "{{English name}} is required." end # ================================ # === check min, max ====== if clean[name].is_a?(String) || clean[name].is_a?(Numeric) case [field[:min], field[:max]].map(&:class) when [NilClass, NilClass] # do nothing when [NilClass, Fixnum] case when clean[name].is_a?(String) && clean[name].size > field[:max] fail! :big, "{{English name}} can't be longer than {{max}} characters." when clean[name].is_a?(Numeric) && clean[name] > field[:max] fail! :big, "{{English name}} can't be higher than {{max}}." end when [Fixnum, NilClass] case when clean[name].is_a?(String) && clean[name].size < field[:min] fail! :short, "{{English name}} can't be shorter than {{min}} characters." when clean[name].is_a?(Numeric) && clean[name] < field[:min] fail! :short, "{{English name}} can't be less than {{min}." end when [Fixnum, Fixnum] case when field?(:chars) && clean[name].size > field[:max] fail! :big, "{{English name}} must be between {{min}} and {{max}} characters." when field?(:chars) && clean[name].size < field[:min] fail! :small, "{{English name}} must be between {{min}} and {{max}} characters." when field?(:numeric) && clean[name] > field[:max] fail! :big, "{{English name}} must be between {{min}} and {{max}}." when field?(:numeric) && clean[name] < field[:min] fail! :small, "{{English name}} must be between {{min}} and {{max}}." end else fail "Unknown values for :min, :max: #{field[:min].inspect}, #{field[:max].inspect}" end end # === if # ================================ # === to_i if necessary ========== if field?(:numeric) if clean[name].nil? && !field[:allow][:null] clean[name] = clean[name].to_i end end # ================================ # === :strip if necessary ======== if field?(:chars) && field[:allow][:strip] && clean[name].is_a?(String) clean[name] = clean[name].strip end # ================================ # === Is value in options? ======= if field[:options] if !field[:options].include?(clean[name]) fail! :mis_match, "{{English name}} can only be: #{field[:options].map(&:inspect).join ', '}" end end # ================================ field[:cleaners].each { |cleaner, args| next if args === false # === cleaner has been disabled. case cleaner when :type case when field?(:numeric) && !clean[name].is_a?(Integer) fail! :wrong_type, "{{English name}} needs to be an integer." when field?(:chars) && !clean[name].is_a?(String) fail! :wrong_type, "{{English name}} needs to be a String." end when :exact_size if clean[name].size != field[:exact_size] case when field?(:chars) || clean[name].is_a?(String) fail! :mis_match, "{{English name}} needs to be {{exact_size}} in length." else fail! :mis_match, "{{English name}} can only be {{exact_size}} in size." end end when :set_to args.each { |meth| clean[name] = (meth.is_a?(Symbol) ? send(meth) : meth.call(self, clean[name])) } when :equal_to args.each { |pair| meth, msg, other = pair target = send(meth) fail!(msg || "{{English name}} must be equal to: #{target.inspect}") unless clean[name] == target } when :included_in arr, msg, other = args fail!(msg || "{{English name}} must be one of these: #{arr.join ', '}") unless arr.include?(clean[name]) when :upcase clean[name] = clean[name].upcase when :match args.each { |regex| case regex when Regexp if clean[name] !~ regex fail!(:mis_match, "{{English name}} is invalid.") end when Proc if !regex.call(self, clean[name]) fail!(:mis_match, "{{English name}} is invalid.") end else fail ArgumentError, "Unknown matcher: #{regex.inspect}" end } else fail "Cleaner not implemented: #{cleaner.inspect}" end # === case cleaner } # === field[:cleaners].each end
clean!(*args)
click to toggle source
# File lib/datoki.rb, line 607 def clean! *args args.each { |name| if @raw[name].nil? && (!@clean || @clean[name].nil?) fail ArgumentError, "#{name.inspect} is not set." else clean name end } end
create?()
click to toggle source
# File lib/datoki.rb, line 875 def create? !!(@raw.has_key?(:create) && @raw[:create]) end
data()
click to toggle source
# File lib/datoki.rb, line 587 def data fail "Data not set." unless @data @data end
db_clean()
click to toggle source
# File lib/datoki.rb, line 600 def db_clean @clean.select { |k, v| meta = self.class.fields[k] !meta || !meta[:pseudo] } end
db_insert()
click to toggle source
# File lib/datoki.rb, line 899 def db_insert k = :db_insert fail "Already inserted." if @db_ops[k] final = db_clean new_data = TABLE().returning(*returning_fields).insert(final).first @data = (@data || {}).merge(new_data) @db_ops[k] = true end
db_update()
click to toggle source
# File lib/datoki.rb, line 909 def db_update k = :db_update fail "Already updated" if @db_ops[k] final = db_clean new_data = TABLE(). returning(*returning_fields). where(primary_key[:name] => final.delete(primary_key[:name])). update(final). first @data = (@data || {}).merge(new_data) @db_ops[:db_update] = true end
delete?()
click to toggle source
# File lib/datoki.rb, line 887 def delete? !!(@raw.has_key?(:delete) && !@raw[:delete]) end
error?()
click to toggle source
# File lib/datoki.rb, line 596 def error? @error && !@error.empty? end
error_msg(type)
click to toggle source
# File lib/datoki.rb, line 796 def error_msg type field[:error_msgs] && field[:error_msgs][type] end
fail!(*args)
click to toggle source
# File lib/datoki.rb, line 800 def fail! *args case args.size when 1 msg = args.shift when 2 msg = error_msg(args.shift) || args.shift else fail ArgumentError, "Unknown args: #{args.inspect}" end err_msg = msg.gsub(/\{\{([a-z\_\-\ ]+)\}\}/i) { |raw| name = $1 case name when "English name" self.class.fields[field_name][:english_name].capitalize.gsub('_', ' ') when "ENGLISH NAME" self.class.fields[field_name][:english_name].upcase.gsub('_', ' ') when "max", "min", "exact_size" self.class.fields[field_name][name.downcase.to_sym] when "val" clean[field_name] else fail "Unknown value: #{name}" end } @error = {:field_name=>field_name, :msg=>err_msg, :value=>clean[field_name]} throw :invalid, self end
field(*args)
click to toggle source
# File lib/datoki.rb, line 843 def field *args case args.size when 0 self.class.fields[field_name] when 1 self.class.fields[args.first] else fail "Unknown args: #{args.inspect}" end end
field?(*args)
click to toggle source
# File lib/datoki.rb, line 854 def field? *args self.class.inspect_field? :type, field_name, *args end
field_name(*args)
click to toggle source
# File lib/datoki.rb, line 830 def field_name *args case args.size when 0 fail "Field name not set." unless @field_name @field_name when 1 fail ArgumentError, "Unknown field: #{args.first.inspect}" unless self.class.fields[args.first] @field_name = args.first else fail "Unknown args: #{args.inspect}" end end
id()
click to toggle source
# File lib/datoki.rb, line 858 def id d = data pk = primary_key[:name] fail "No primary key set yet." unless d.has_key?(pk) d[pk] end
new?()
click to toggle source
# File lib/datoki.rb, line 871 def new? !@data end
primary_key()
click to toggle source
read?()
click to toggle source
# File lib/datoki.rb, line 879 def read? !!(@raw.has_key?(:read) && @raw[:read]) end
returning_fields()
click to toggle source
# File lib/datoki.rb, line 895 def returning_fields self.class.returning_fields end
skip(name)
click to toggle source
# File lib/datoki.rb, line 592 def skip name @skips[name] = true end
update?()
click to toggle source
# File lib/datoki.rb, line 883 def update? !!(@raw.has_key?(:update) && @raw[:update]) end