<commit_before>module DTK
  class ServiceModule < Model
    r8_nested_require('service', 'dsl')
    r8_nested_require('service', 'service_add_on')
    r8_nested_require('module', 'auto_import')

    extend ModuleClassMixin
    extend AutoImport
    include ModuleMixin
    extend DSLClassMixin
    include DSLMixin
    include ModuleRefs::Mixin

    ### standard get methods
    def get_assemblies
      get_objs_helper(:assemblies, :component)
    end

    def get_augmented_assembly_nodes
      get_objs_helper(:assembly_nodes, :node, augmented: true)
    end

    def get_referenced_component_refs
      ndx_ret = {}
      get_objs(cols: [:component_refs]).each do |r|
        cmp_ref = r[:component_ref]
        ndx_ret[cmp_ref[:id]] ||= cmp_ref
      end
      ndx_ret.values
    end

    def assembly_ref(assembly_name, version_field = nil)
      assembly_ref = Namespace.join_namespace(module_namespace(), "#{module_name()}-#{assembly_name}")
      if version_field
        assembly_ref = assembly_ref__add_version(assembly_ref, version_field)
      end
      assembly_ref
    end

    def assembly_ref__add_version(assembly_ref, version_field)
      version = ModuleBranch.version_from_version_field(version_field)
      "#{assembly_ref}--#{version}"
    end

    private :assembly_ref__add_version

    def list_component_modules(opts = Opts.new)
      get_referenced_component_modules(opts).sort { |a, b| a[:display_name] <=> b[:display_name] }
    end

    def get_referenced_component_modules(opts = Opts.new)
      # TODO: alternative is to get this by getting the module_refs
      ret = []
      cmp_refs = get_referenced_component_refs()
      return ret if cmp_refs.empty?
      project = get_project()
      ret = ComponentRef.get_referenced_component_modules(project, cmp_refs)

      if opts.array(:detail_to_include).include?(:versions)
        ndx_versions = get_component_module_refs().version_objs_indexed_by_modules()

        ret.each do |mod|
          if version_obj = ndx_versions[mod.module_name()]
            mod[:version] = version_obj
          end
        end
      end

      ret
    end

    ### end: get methods

    def self.model_type
      :service_module
    end

    def self.filter_list!(rows)
      rows.reject! { |r| Workspace.is_workspace_service_module?(r) }
      rows
    end

    def delete_object
      assembly_templates = get_assembly_templates()

      assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)
      unless assoc_assemblies.empty?
        assembly_names = assoc_assemblies.map { |a| a[:display_name] }
        fail ErrorUsage.new("Cannot delete a service module if one or more of its service instances exist in a target (#{assembly_names.join(',')})")
      end
      repos = get_repos()
      repos.each { |repo| RepoManager.delete_repo(repo) }
      delete_instances(repos.map(&:id_handle))

      # need to explicitly delete nodes since nodes' parents are not the assembly
      Assembly::Template.delete_assemblies_nodes(assembly_templates.map(&:id_handle))

      delete_instance(id_handle())
      { module_name: module_name }
    end

    def delete_version?(version, opts = {})
      delete_version(version, opts.merge(no_error_if_does_not_exist: true))
    end

    def delete_version(version, opts = {})
      ret = { module_name: module_name() }
      unless module_branch  = get_module_branch_matching_version(version)
        if opts[:no_error_if_does_not_exist]
          return ret
        else
          fail ErrorUsage.new("Version '#{version}' for specified component module does not exist")
        end
      end

      unless opts[:donot_delete_meta]
        assembly_templates = module_branch.get_assemblies()
        assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)
        unless assoc_assemblies.empty?
          assembly_names = assoc_assemblies.map { |a| a[:display_name] }
          fail ErrorUsage.new("Cannot delete a service module if one or more of its service instances exist in a target (#{assembly_names.join(',')})")
        end
        Assembly::Template.delete_assemblies_nodes(assembly_templates.map(&:id_handle))
      end

      id_handle = module_branch.id_handle()
      module_branch.delete_instance(id_handle)
      ret
    end

    def delete_version_or_module(version)
      module_branches = get_module_branches()

      if module_branches.size > 1
        delete_version(version)
      else
        unless module_branch = get_module_branch_matching_version(version)
          fail ErrorUsage.new("Version '#{version}' for specified service module does not exist!") if version
          fail ErrorUsage.new("Base version for specified service module does not exist. You have to specify version you want to delete!")
        end
        delete_object()
      end
    end

    def get_assembly_instances
      assembly_templates = get_assembly_templates()
      assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)

      assoc_assemblies.each do |assoc_assembly|
        assembly_template = assembly_templates.select { |at| at[:id] == assoc_assembly[:ancestor_id] }
        nodes = assembly_template.first[:nodes]
        assoc_assembly[:nodes] = nodes
      end
    end

    def get_assembly_templates(opts = {})
      sp_hash = {
        cols: [:module_branches]
      }
      mb_idhs = get_objs(sp_hash).map { |r| r[:module_branch].id_handle() }
      opts.merge!(filter: [:oneof, :module_branch_id, mb_idhs.map(&:get_id)])
      if project = get_project()
        opts.merge!(project_idh: project.id_handle())
      end
      ndx_ret = Assembly::Template.get(model_handle(:component), opts).inject({}) { |h, r| h.merge(r[:id] => r) }
      Assembly::Template.get_nodes(ndx_ret.values.map(&:id_handle)).each do |node|
        next if node.is_assembly_wide_node?()
        assembly = ndx_ret[node[:assembly_id]]
        (assembly[:nodes] ||= []) << node
      end
      ndx_ret.values
    end

    def list_assembly_templates(version = 'master')
      version_filter =
        if version.eql?('master')
          [:or, [:eq, :version, version], [:eq, :version, nil]]
        else<commit_msg>Match empty version field on list-assemblies<commit_after>module DTK
  class ServiceModule < Model
    r8_nested_require('service', 'dsl')
    r8_nested_require('service', 'service_add_on')
    r8_nested_require('module', 'auto_import')

    extend ModuleClassMixin
    extend AutoImport
    include ModuleMixin
    extend DSLClassMixin
    include DSLMixin
    include ModuleRefs::Mixin

    ### standard get methods
    def get_assemblies
      get_objs_helper(:assemblies, :component)
    end

    def get_augmented_assembly_nodes
      get_objs_helper(:assembly_nodes, :node, augmented: true)
    end

    def get_referenced_component_refs
      ndx_ret = {}
      get_objs(cols: [:component_refs]).each do |r|
        cmp_ref = r[:component_ref]
        ndx_ret[cmp_ref[:id]] ||= cmp_ref
      end
      ndx_ret.values
    end

    def assembly_ref(assembly_name, version_field = nil)
      assembly_ref = Namespace.join_namespace(module_namespace(), "#{module_name()}-#{assembly_name}")
      if version_field
        assembly_ref = assembly_ref__add_version(assembly_ref, version_field)
      end
      assembly_ref
    end

    def assembly_ref__add_version(assembly_ref, version_field)
      version = ModuleBranch.version_from_version_field(version_field)
      "#{assembly_ref}--#{version}"
    end

    private :assembly_ref__add_version

    def list_component_modules(opts = Opts.new)
      get_referenced_component_modules(opts).sort { |a, b| a[:display_name] <=> b[:display_name] }
    end

    def get_referenced_component_modules(opts = Opts.new)
      # TODO: alternative is to get this by getting the module_refs
      ret = []
      cmp_refs = get_referenced_component_refs()
      return ret if cmp_refs.empty?
      project = get_project()
      ret = ComponentRef.get_referenced_component_modules(project, cmp_refs)

      if opts.array(:detail_to_include).include?(:versions)
        ndx_versions = get_component_module_refs().version_objs_indexed_by_modules()

        ret.each do |mod|
          if version_obj = ndx_versions[mod.module_name()]
            mod[:version] = version_obj
          end
        end
      end

      ret
    end

    ### end: get methods

    def self.model_type
      :service_module
    end

    def self.filter_list!(rows)
      rows.reject! { |r| Workspace.is_workspace_service_module?(r) }
      rows
    end

    def delete_object
      assembly_templates = get_assembly_templates()

      assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)
      unless assoc_assemblies.empty?
        assembly_names = assoc_assemblies.map { |a| a[:display_name] }
        fail ErrorUsage.new("Cannot delete a service module if one or more of its service instances exist in a target (#{assembly_names.join(',')})")
      end
      repos = get_repos()
      repos.each { |repo| RepoManager.delete_repo(repo) }
      delete_instances(repos.map(&:id_handle))

      # need to explicitly delete nodes since nodes' parents are not the assembly
      Assembly::Template.delete_assemblies_nodes(assembly_templates.map(&:id_handle))

      delete_instance(id_handle())
      { module_name: module_name }
    end

    def delete_version?(version, opts = {})
      delete_version(version, opts.merge(no_error_if_does_not_exist: true))
    end

    def delete_version(version, opts = {})
      ret = { module_name: module_name() }
      unless module_branch  = get_module_branch_matching_version(version)
        if opts[:no_error_if_does_not_exist]
          return ret
        else
          fail ErrorUsage.new("Version '#{version}' for specified component module does not exist")
        end
      end

      unless opts[:donot_delete_meta]
        assembly_templates = module_branch.get_assemblies()
        assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)
        unless assoc_assemblies.empty?
          assembly_names = assoc_assemblies.map { |a| a[:display_name] }
          fail ErrorUsage.new("Cannot delete a service module if one or more of its service instances exist in a target (#{assembly_names.join(',')})")
        end
        Assembly::Template.delete_assemblies_nodes(assembly_templates.map(&:id_handle))
      end

      id_handle = module_branch.id_handle()
      module_branch.delete_instance(id_handle)
      ret
    end

    def delete_version_or_module(version)
      module_branches = get_module_branches()

      if module_branches.size > 1
        delete_version(version)
      else
        unless module_branch = get_module_branch_matching_version(version)
          fail ErrorUsage.new("Version '#{version}' for specified service module does not exist!") if version
          fail ErrorUsage.new("Base version for specified service module does not exist. You have to specify version you want to delete!")
        end
        delete_object()
      end
    end

    def get_assembly_instances
      assembly_templates = get_assembly_templates()
      assoc_assemblies = self.class.get_associated_target_instances(assembly_templates)

      assoc_assemblies.each do |assoc_assembly|
        assembly_template = assembly_templates.select { |at| at[:id] == assoc_assembly[:ancestor_id] }
        nodes = assembly_template.first[:nodes]
        assoc_assembly[:nodes] = nodes
      end
    end

    def get_assembly_templates(opts = {})
      sp_hash = {
        cols: [:module_branches]
      }
      mb_idhs = get_objs(sp_hash).map { |r| r[:module_branch].id_handle() }
      opts.merge!(filter: [:oneof, :module_branch_id, mb_idhs.map(&:get_id)])
      if project = get_project()
        opts.merge!(project_idh: project.id_handle())
      end
      ndx_ret = Assembly::Template.get(model_handle(:component), opts).inject({}) { |h, r| h.merge(r[:id] => r) }
      Assembly::Template.get_nodes(ndx_ret.values.map(&:id_handle)).each do |node|
        next if node.is_assembly_wide_node?()
        assembly = ndx_ret[node[:assembly_id]]
        (assembly[:nodes] ||= []) << node
      end
      ndx_ret.values
    end

    def list_assembly_templates(version = 'master')
      version_filter =
        if version.eql?('master')
          [:or, [:eq, :version, version], [:eq, :version, nil], [:eq, :version, '']]
        else
{'fraction_non_alphanumeric': 0.09480957737425678, 'fraction_numerical': 0.0006427767957576731, 'mean_word_length': 3.2221845318860245, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4497415', 'n_tokens_mistral': 3842, 'n_tokens_neox': 3753, 'n_words': 782}