yamotech/activerecord-dbt

View on GitHub
lib/active_record/dbt/column/yml.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module ActiveRecord
  module Dbt
    module Column
      class Yml
        include ActiveRecord::Dbt::DataType::Mapper
        include ActiveRecord::Dbt::I18nWrapper::Translate
        include ActiveRecord::Dbt::Validation::TableNameValidator

        using ActiveRecord::Dbt::CoreExt::ActiveRecordExt

        attr_reader :table_name, :column, :column_data_test, :primary_keys

        # MEMO: GitHub copilot taught me this.
        SQL_KEYWORDS = %w[
          ADD ALL ALTER AND ANY AS ASC BACKUP BETWEEN CASE CHECK COLUMN CONSTRAINT CREATE
          DATABASE DEFAULT DELETE DESC DISTINCT DROP EXEC EXISTS FOREIGN FROM FULL GROUP
          HAVING IN INDEX INNER INSERT INTO IS JOIN LEFT LIKE LIMIT NOT NULL OR ORDER OUTER
          PRIMARY PROCEDURE RIGHT ROWNUM SELECT SET TABLE TOP TRUNCATE UNION UNIQUE UPDATE
          VALUES VIEW WHERE
        ].freeze

        delegate :name, :comment, to: :column, prefix: true
        delegate :source_config, to: :@config

        def initialize(table_name, column, column_data_test, primary_keys: [])
          @config = ActiveRecord::Dbt::Config.instance
          @table_name = validate_table_name(table_name, @config)
          @column = column
          @column_data_test = column_data_test
          @primary_keys = primary_keys
        end

        def properties
          {
            'name' => column_name,
            'description' => description,
            'quote' => quote?,
            'data_type' => data_type(column.type),
            **column_overrides.except(:data_tests),
            'data_tests' => column_data_test.properties
          }.compact
        end

        private

        def description
          @description ||=
            column_description ||
            translated_attribute_name ||
            column_comment ||
            key_column_name ||
            default_column_description ||
            "Write a description of the '#{table_name}.#{column_name}' column."
        end

        def column_description
          source_config.dig(:table_descriptions, table_name, :columns, column_name)
        end

        def key_column_name
          column_name if primary_key? || foreign_key?
        end

        def primary_key?
          primary_keys.include?(column_name)
        end

        def foreign_key?
          ActiveRecord::Base.connection.foreign_key_exists?(table_name, column: column_name)
        end

        def default_column_description
          source_config.dig(:defaults, :table_descriptions, :columns, :description)
                       &.gsub(/{{\s*table_name\s*}}/, table_name)
                       &.gsub(/{{\s*column_name\s*}}/, column_name)
        end

        # MEMO: [quote | dbt Developer Hub](https://docs.getdbt.com/reference/resource-properties/quote)
        def quote?
          SQL_KEYWORDS.include?(column_name.upcase) ? true : nil
        end

        def column_overrides
          @column_overrides ||=
            source_config.dig(:table_overrides, table_name, :columns, column_name) ||
            {}
        end
      end
    end
  end
end