module Isomorfeus module Data module FieldSupport def self.included(base) base.instance_exec do def field_types # determines how the item is stored in the index @field_types ||= {} end def field_options # options for the index @field_options ||= {} end def field_conditions @field_conditions ||= {} end def _register_field(name, type, options) field_options[name] = {} field_options[name][:default_boost] = options.delete(:default_boost) if options.key?(:default_boost) field_options[name][:default_boost] = options.delete(:default_boost) if options.key?(:boost) field_options[name][:index] = options.delete(:index) { :no } field_options[name][:store] = options.delete(:store) if options.key?(:store) field_options[name][:compress] = options.delete(:compress) if options.key?(:compress) if field_options[name][:index] == :yes field_options[name][:term_vector] = options.delete(:term_vector) { type == :text_field ? :with_positions_offsets : :no } elsif field_options[name][:index] == :no field_options[name][:term_vector] = :no end field_conditions[name] = options field_types[name] = type end def text_field(name, options = {}) field(name, :text_field, options) end def attribute(name, options = {}) field(name, :attribute, options) end alias embed attribute def object(name, options = {}) default_options = { is_a: LucidObject::Mixin, allow_nil: true } field(name, :object, default_options.merge(options)) end alias reference object def field?(field_name) field_options.key?(field_name) end def text_field?(field_name) field_types[field_name] == :text_field end def attribute?(attr_name) field_types[attr_name] == :attribute end def object?(obj_name) field_types[obj_name] == :object end def validate_field!(field_name, val) raise "no such field" unless field?(field_name) Isomorfeus::Props::Validator.new(self.name, field_name, val, field_conditions[field_name]).validate! end def valid_field?(field_name, val) validate_field!(field_name, val) rescue false end def valid_text_field?(field_name, val) return valid_field?(field_name, val) if text_field?(field_name) false rescue false end def valid_attribute?(attr_name, val) return valid_field?(attr_name, val) if attribute?(attr_name) false rescue false end alias valid_embed? valid_attribute? def valid_object?(obj_name, val) return valid_field?(obj_name, val) if object?(obj_name) false rescue false end alias valid_reference? valid_object? def validate Isomorfeus::Props::ValidateHashProxy.new end def _validate_field(field_name, val) Isomorfeus.raise_error(message: "#{self.name}: No such text_field, attribute or object declared: '#{field_name}'!") unless field_conditions.key?(field_name) Isomorfeus::Props::Validator.new(self.name, field_name, val, field_conditions[field_name]).validated_value end def _validate_fields(fields) field_conditions.each_key do |field_name| if field_conditions[field_name].key?(:required) && field_conditions[field_name][:required] && !fields.key?(field_name) Isomorfeus.raise_error(message: "Required #{field_types[field_name]} #{field_name} not given!") end fields[field_name] = _validate_field(field_name, fields[field_name]) end end end def _validate_field(field_name, val) self.class._validate_field(field_name, val) end def _validate_fields(fields) self.class._validate_fields(fields) end if RUBY_ENGINE == 'opal' base.instance_exec do def field(name, type, options) _register_field(name, type, options) if type == :object define_method(name) do _get_object(name) end else define_method(name) do _get_field(name) end end define_method("#{name}=") do |val| val = _validate_field(name, val) changed! @_changed_fields[name] = val end end end def validate_fields_function %x{ if (typeof self.validate_fields_function === 'undefined') { self.validate_fields_function = function(fields_object) { try { self.$_validate_fields(Opal.Hash.$new(fields_object)) } catch (e) { return e.message; } } } return self.validate_fields_function; } end def validate_field_function(field_name) function_name = "validate_field_#{field_name}_function" %x{ if (typeof self[function_name] === 'undefined') { self[function_name] = function(value) { try { self.$_validate_field(field_name, value); } catch (e) { return e.message; } } } return self[function_name]; } end def _get_field(name) return @_changed_fields[name] if @_changed_fields.key?(name) path = @_store_path + [name] result = Redux.fetch_by_path(*path) %x{ if (result === null) { return nil; } else { return result; } } end def _get_object(name) return @_changed_fields[name] if @_changed_fields.key?(name) return @_objects[name] if @_objects.key?(name) path = @_store_path + [name] sid_or_array = Redux.fetch_by_path(*path) return nil if `(sid_or_array === null)` @_objects[name] = Isomorfeus.instance_from_sid(sid_or_array) if sid_or_array end def fields raw_fields = Redux.fetch_by_path(*@_store_path) hash = Hash.new(raw_fields) hash.merge!(@_changed_fields) if @_changed_fields hash end def _get_selected_fields sel_fields = fields.dup self.class.field_types.each do |field, type| sel_fields[field] = sel_fields[field]&.sid if type == :object end sel_fields end else base.instance_exec do def field(name, type, options) _register_field(name, type, options) define_method(name) do @_raw_fields[name] end define_method("#{name}=") do |val| val = _validate_field(name, val) changed! @_raw_fields[name] = val end end end def fields @_raw_fields end def _get_selected_fields sel_fields = fields.transform_keys(&:to_s) ft = self.class.field_types self.class.field_conditions.each do |field, options| field_s = field.to_s if options[:server_only] sel_fields.delete(field_s) elsif ft[field] == :object sel_fields[field_s] = sel_fields[field_s]&.sid end end sel_fields end end end end end end