class ReeDao::Associations

def self.sync_mode?

def self.sync_mode?
  ReeDao.load_sync_associations_enabled?
end

def association(assoc_type, assoc_name, __opts, &block)

def association(assoc_type, assoc_name, __opts, &block)
  if parent_dao.nil? || parent_dao.db.in_transaction? || self.class.sync_mode?
    return if association_is_not_included?(assoc_name) || list.empty?
    association = Association.new(self, parent_dao, list, **global_opts)
    if assoc_type == :field
      association.handle_field(__opts)
    else
      association.load(assoc_type, assoc_name, **get_assoc_opts(__opts), &block)
    end
  else
    if association_is_not_included?(assoc_name) || list.empty?
      return { association_threads: @assoc_threads, field_threads: @field_threads }
    end
    association = Association.new(self, parent_dao, list, **global_opts)
    if assoc_type == :field
      field_proc = __opts
      {
        association_threads: @assoc_threads,
        field_threads: @field_threads << [
          association, field_proc
        ]
      }
    else
      {
        association_threads: @assoc_threads << [
          association, assoc_type, assoc_name, get_assoc_opts(__opts), block
        ],
        field_threads: @field_threads
      }
    end
  end
end

def association_is_not_included?(assoc_name)

def association_is_not_included?(assoc_name)
  return false if !only && !except
  if only
    return false if only && only.include?(assoc_name)
    if only && !only.include?(assoc_name)
      if autoload_children
        return true if except && except.include?(assoc_name)
        return false
      end
      return true
    end
  end
  if except
    return true if except && except.include?(assoc_name)
    return false if except && !except.include?(assoc_name)
  end
end

def belongs_to(assoc_name, __opts = nil, &block)

def belongs_to(assoc_name, __opts = nil, &block)
  association(__method__, assoc_name, __opts, &block)
end

def field(assoc_name, proc)

def field(assoc_name, proc)
  association(__method__, assoc_name, proc)
end

def get_assoc_opts(opts)

def get_assoc_opts(opts)
  if opts.is_a?(Proc)
    opts.call
  elsif opts.is_a?(Sequel::Dataset)
    { scope: opts }
  else
    {}
  end
end

def has_many(assoc_name, __opts = nil, &block)

def has_many(assoc_name, __opts = nil, &block)
  association(__method__, assoc_name, __opts, &block)
end

def has_one(assoc_name, __opts = nil, &block)

def has_one(assoc_name, __opts = nil, &block)
  association(__method__, assoc_name, __opts, &block)
end

def initialize(agg_caller, list, local_vars, parent_dao, autoload_children = false, **opts)

def initialize(agg_caller, list, local_vars, parent_dao, autoload_children = false, **opts)
  @agg_caller = agg_caller
  @list = list
  @local_vars = local_vars
  @global_opts = opts || {}
  @only = opts[:only] if opts[:only]
  @except = opts[:except] if opts[:except]
  @parent_dao = parent_dao
  @autoload_children = autoload_children
  if @only && @except
    shared_keys = @only.intersection(@except)
    if shared_keys.size > 0
      raise ArgumentError.new("you can't use both :only and :except for #{shared_keys.map { "\"#{_1}\"" }.join(", ")} keys")
    end
  end
  if !self.class.sync_mode?
    @assoc_threads = []
    @field_threads = []
  end
  local_vars.each do |k, v|
    instance_variable_set(k, v)
    self.class.define_method k.to_s.gsub('@', '') do
      v
    end
  end
end

def method_missing(method, *args, &block)

def method_missing(method, *args, &block)
  return super if !agg_caller.private_methods(false).include?(method)
  agg_caller.send(method, *args, &block)
end