lib/canvas_sync/record.rb



require_relative 'concerns/sync_mapping'

module CanvasSync
  module Record
    extend ActiveSupport::Concern
    include CanvasSync::Concerns::SyncMapping

    def self.registered_features
      @canvas_sync_features ||= {}
    end

    def self.define_feature(modul, feature_ident = nil, models: nil, default: false, &blk)
      feature_ident = modul.name.demodulize.underscore if feature_ident.nil?
      if models == nil
        pmod = _get_module_parent(modul)
        models = pmod.name.demodulize if pmod && _get_module_parent(pmod) == CanvasSync::Concerns
      end

      @canvas_sync_features ||= {}
      @canvas_sync_features[feature_ident] = {
        name: feature_ident,
        module: modul,
        default: default,
        models: Array.wrap(models).map(&:to_s),
        setup: blk || ->{ include modul },
      }
    end

    def self._get_module_parent(modul)
      modul.respond_to?(:parent) ? modul.parent : modul.module_parent
    end

    class_methods do
      def applicable_canvas_sync_features
        @applicable_canvas_sync_features ||= begin
          relev_feats = {}
          CanvasSync::Record.registered_features.each do |k, cfg|
            next if cfg[:models].present? && !cfg[:models].include?(self.name.demodulize)
            relev_feats[k] = cfg
          end
          relev_feats
        end
      end

      def canvas_sync_feature(feature, config = nil)
        feat = applicable_canvas_sync_features[feature]

        if !feat
          raise "Unkown feature :#{feature} for model #{self}"
        end

        setup = feat[:setup]
        if setup.arity != 0
          instance_exec(config, &setup)
        elsif config.present?
          raise ArgumentError, "Feature #{feature} does not accept configuration"
        else
          instance_exec(&setup)
        end
      end

      def canvas_sync_features(*args, skip: [], **kwargs)
        features = {}

        include_defaults = args.length == 0 || args.include?(:defaults)
        if include_defaults
          applicable_canvas_sync_features.each do |key, cfg|
            next if skip.include?(key)

            case cfg[:default]
            when true
              features[key] = {}
            when Proc
              features[key] = {} if instance_exec(&cfg[:default])
            end
          end
        end

        args.each do |a|
          next if a == :defaults
          features[a] ||= {}
        end

        kwargs.each do |key, opts|
          if opts == false
            features.delete(key)
          elsif opts == true
            features[key] ||= {}
          else
            features[key] = opts
          end
        end

        features.each do |key, opts|
          canvas_sync_feature(key, opts)
        end
      end
    end

    included do
      define_model_callbacks :sync_import

      begin
        if column_names.include?("canvas_sync_batch_id")
          belongs_to :canvas_sync_batch, foreign_key: :canvas_sync_batch_id, class_name: "CanvasSync::SyncBatch", optional: true
        end
      rescue PG::UndefinedTable
      end
    end
  end
end