activerecord-dbt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +921 -0
  4. data/Rakefile +5 -0
  5. data/lib/active_record/dbt/column/column.rb +84 -0
  6. data/lib/active_record/dbt/column/test.rb +61 -0
  7. data/lib/active_record/dbt/column/testable/accepted_values_testable.rb +59 -0
  8. data/lib/active_record/dbt/column/testable/not_null_testable.rb +23 -0
  9. data/lib/active_record/dbt/column/testable/relationships_testable.rb +49 -0
  10. data/lib/active_record/dbt/column/testable/unique_testable.rb +37 -0
  11. data/lib/active_record/dbt/config.rb +45 -0
  12. data/lib/active_record/dbt/configuration/data_sync.rb +15 -0
  13. data/lib/active_record/dbt/configuration/logger.rb +41 -0
  14. data/lib/active_record/dbt/configuration/parser.rb +15 -0
  15. data/lib/active_record/dbt/configuration/used_dbt_package.rb +25 -0
  16. data/lib/active_record/dbt/dbt_package/dbt_utils/table/testable/unique_combination_of_columns_testable.rb +42 -0
  17. data/lib/active_record/dbt/dbt_package/dbterd/column/testable/relationships_meta_relationship_type.rb +138 -0
  18. data/lib/active_record/dbt/factory/columns_factory.rb +31 -0
  19. data/lib/active_record/dbt/factory/model/staging_factory.rb +22 -0
  20. data/lib/active_record/dbt/factory/source_factory.rb +16 -0
  21. data/lib/active_record/dbt/factory/table_factory.rb +16 -0
  22. data/lib/active_record/dbt/factory/tables_factory.rb +15 -0
  23. data/lib/active_record/dbt/model/staging/base.rb +73 -0
  24. data/lib/active_record/dbt/model/staging/sql.rb +43 -0
  25. data/lib/active_record/dbt/model/staging/yml.rb +108 -0
  26. data/lib/active_record/dbt/railtie.rb +8 -0
  27. data/lib/active_record/dbt/source/yml.rb +37 -0
  28. data/lib/active_record/dbt/table/base.rb +16 -0
  29. data/lib/active_record/dbt/table/test.rb +19 -0
  30. data/lib/active_record/dbt/table/yml.rb +75 -0
  31. data/lib/active_record/dbt/version.rb +7 -0
  32. data/lib/active_record/dbt.rb +17 -0
  33. data/lib/generators/active_record/dbt/config/USAGE +9 -0
  34. data/lib/generators/active_record/dbt/config/config_generator.rb +30 -0
  35. data/lib/generators/active_record/dbt/config/templates/source_config.yml.tt +68 -0
  36. data/lib/generators/active_record/dbt/initializer/USAGE +8 -0
  37. data/lib/generators/active_record/dbt/initializer/initializer_generator.rb +15 -0
  38. data/lib/generators/active_record/dbt/initializer/templates/dbt.rb +10 -0
  39. data/lib/generators/active_record/dbt/source/USAGE +8 -0
  40. data/lib/generators/active_record/dbt/source/source_generator.rb +22 -0
  41. data/lib/generators/active_record/dbt/staging_model/USAGE +9 -0
  42. data/lib/generators/active_record/dbt/staging_model/staging_model_generator.rb +38 -0
  43. data/lib/generators/active_record/dbt/staging_model/templates/staging_model.sql.tt +29 -0
  44. data/lib/tasks/active_record/dbt_tasks.rake +6 -0
  45. metadata +133 -0
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'bundler/gem_tasks'
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ class Column
7
+ attr_reader :table_name, :column, :column_test, :primary_keys
8
+
9
+ delegate :name, :comment, to: :column, prefix: true
10
+ delegate :source_config, to: :@config
11
+
12
+ def initialize(table_name, column, column_test, primary_keys: [])
13
+ @table_name = table_name
14
+ @column = column
15
+ @column_test = column_test
16
+ @primary_keys = primary_keys
17
+ @config = ActiveRecord::Dbt::Config.instance
18
+ end
19
+
20
+ def config
21
+ {
22
+ 'name' => column_name,
23
+ 'description' => description,
24
+ 'meta' => { 'column_type' => column.type.to_s },
25
+ **column_overrides.except(:tests),
26
+ 'tests' => column_test.config
27
+ }.compact
28
+ end
29
+
30
+ private
31
+
32
+ def description
33
+ @description ||=
34
+ column_description ||
35
+ translated_attribute_name ||
36
+ column_comment ||
37
+ key_column_name ||
38
+ default_column_description ||
39
+ "Write a description of the '#{table_name}.#{column_name}' column."
40
+ end
41
+
42
+ def column_description
43
+ source_config.dig(:table_descriptions, table_name, :columns, column_name)
44
+ end
45
+
46
+ def translated_attribute_name
47
+ translated_column_name || translated_default_column_name
48
+ end
49
+
50
+ def translated_column_name
51
+ I18n.t("activerecord.attributes.#{table_name.singularize}.#{column_name}", default: nil)
52
+ end
53
+
54
+ def translated_default_column_name
55
+ I18n.t("attributes.#{column_name}", default: nil)
56
+ end
57
+
58
+ def key_column_name
59
+ column_name if primary_key? || foreign_key?
60
+ end
61
+
62
+ def primary_key?
63
+ primary_keys.include?(column_name)
64
+ end
65
+
66
+ def foreign_key?
67
+ ActiveRecord::Base.connection.foreign_key_exists?(table_name, column: column_name)
68
+ end
69
+
70
+ def default_column_description
71
+ source_config.dig(:defaults, :table_descriptions, :columns, :description)
72
+ &.gsub(/{{\s*table_name\s*}}/, table_name)
73
+ &.gsub(/{{\s*column_name\s*}}/, column_name)
74
+ end
75
+
76
+ def column_overrides
77
+ @column_overrides ||=
78
+ source_config.dig(:table_overrides, table_name, :columns, column_name) ||
79
+ {}
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ class Test
7
+ include ActiveRecord::Dbt::Column::Testable::AcceptedValuesTestable
8
+ include ActiveRecord::Dbt::Column::Testable::NotNullTestable
9
+ include ActiveRecord::Dbt::Column::Testable::RelationshipsTestable
10
+ include ActiveRecord::Dbt::Column::Testable::UniqueTestable
11
+
12
+ attr_reader :table_name, :column, :primary_keys, :foreign_keys
13
+
14
+ delegate :name, to: :column, prefix: true
15
+ delegate :source_config, to: :@config
16
+
17
+ def initialize(table_name, column, primary_keys: [], foreign_keys: [{}])
18
+ @table_name = table_name
19
+ @column = column
20
+ @primary_keys = primary_keys
21
+ @foreign_keys = foreign_keys
22
+ @config = ActiveRecord::Dbt::Config.instance
23
+ end
24
+
25
+ def config
26
+ (tests.keys | tests_overrides_hash.keys).map do |key|
27
+ tests_overrides_hash[key] || tests[key]
28
+ end.presence
29
+ end
30
+
31
+ private
32
+
33
+ def tests
34
+ {
35
+ 'unique_test' => unique_test,
36
+ 'not_null_test' => not_null_test,
37
+ 'relationships_test' => relationships_test,
38
+ 'accepted_values_test' => accepted_values_test
39
+ }.compact
40
+ end
41
+
42
+ def tests_overrides_hash
43
+ @tests_overrides_hash ||=
44
+ tests_overrides.index_by do |tests_override|
45
+ "#{extract_key(tests_override)}_test"
46
+ end
47
+ end
48
+
49
+ def extract_key(item)
50
+ item.is_a?(Hash) ? item.keys.first : item
51
+ end
52
+
53
+ def tests_overrides
54
+ @tests_overrides ||=
55
+ source_config.dig(:table_overrides, table_name, :columns, column_name, :tests) ||
56
+ []
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ module Testable
7
+ module AcceptedValuesTestable
8
+ REQUIRED_ACCEPTED_VALUES_TESTABLE_METHODS = %i[@config column table_name column_name].freeze
9
+
10
+ delegate :type, to: :column, prefix: true
11
+ delegate :add_log, to: :@config
12
+
13
+ REQUIRED_ACCEPTED_VALUES_TESTABLE_METHODS.each do |method_name|
14
+ define_method(method_name) do
15
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
16
+ end
17
+ end
18
+
19
+ def accepted_values_test
20
+ return nil unless column_type == :boolean || enum_values.present?
21
+
22
+ {
23
+ 'accepted_values' => {
24
+ 'values' => values,
25
+ 'quote' => quote?
26
+ }
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ def values
33
+ column_type == :boolean ? [true, false] : enum_accepted_values
34
+ end
35
+
36
+ def enum_accepted_values
37
+ enum_values.map { |key| quote? ? key.to_s : key }
38
+ end
39
+
40
+ def enum_values
41
+ @enum_values ||= enums[column_name]&.values
42
+ end
43
+
44
+ def enums
45
+ table_name.singularize.classify.constantize.defined_enums
46
+ rescue NameError => e
47
+ add_log(self.class, e)
48
+
49
+ {}
50
+ end
51
+
52
+ def quote?
53
+ @quote ||= %i[integer boolean].exclude?(column_type)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ module Testable
7
+ module NotNullTestable
8
+ REQUIRED_NOT_NULL_TESTABLE_METHODS = %i[column].freeze
9
+
10
+ REQUIRED_NOT_NULL_TESTABLE_METHODS.each do |method_name|
11
+ define_method(method_name) do
12
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
13
+ end
14
+ end
15
+
16
+ def not_null_test
17
+ column.null == true ? nil : 'not_null'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ module Testable
7
+ module RelationshipsTestable
8
+ REQUIRED_RELATIONSHIPS_TESTABLE_METHODS = %i[@config foreign_keys column_name].freeze
9
+
10
+ include ActiveRecord::Dbt::DbtPackage::Dbterd::Column::Testable::RelationshipsMetaRelationshipType
11
+
12
+ delegate :source_name, :data_sync_delayed?, to: :@config
13
+ delegate :to_table, to: :foreign_key
14
+
15
+ REQUIRED_RELATIONSHIPS_TESTABLE_METHODS.each do |method_name|
16
+ define_method(method_name) do
17
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
18
+ end
19
+ end
20
+
21
+ def relationships_test
22
+ return nil if foreign_key.blank?
23
+
24
+ {
25
+ 'relationships' => {
26
+ 'severity' => data_sync_delayed? ? 'warn' : nil,
27
+ 'to' => "source('#{source_name}', '#{to_table}')",
28
+ 'field' => primary_key,
29
+ 'meta' => relationships_meta_relationship_type
30
+ }.compact
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ def primary_key
37
+ foreign_key.dig(:options, :primary_key)
38
+ end
39
+
40
+ def foreign_key
41
+ @foreign_key ||= foreign_keys.find do |fk|
42
+ fk.dig(:options, :column) == column_name
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Column
6
+ module Testable
7
+ module UniqueTestable
8
+ REQUIRED_UNIQUE_TESTABLE_METHODS = %i[table_name column_name primary_keys].freeze
9
+
10
+ REQUIRED_UNIQUE_TESTABLE_METHODS.each do |method_name|
11
+ define_method(method_name) do
12
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
13
+ end
14
+ end
15
+
16
+ def unique_test
17
+ unique? ? 'unique' : nil
18
+ end
19
+
20
+ private
21
+
22
+ def unique?
23
+ primary_keys.include?(column_name) || unique_columns.include?(column_name)
24
+ end
25
+
26
+ def unique_columns
27
+ ActiveRecord::Base.connection.indexes(table_name).each_with_object([]) do |index, array|
28
+ if index.unique == true && (unique_indexes = index.columns).size == 1
29
+ array << unique_indexes.first
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module ActiveRecord
6
+ module Dbt
7
+ class Config
8
+ include Singleton
9
+
10
+ include ActiveRecord::Dbt::Configuration::DataSync
11
+ include ActiveRecord::Dbt::Configuration::Logger
12
+ include ActiveRecord::Dbt::Configuration::Parser
13
+ include ActiveRecord::Dbt::Configuration::UsedDbtPackage
14
+
15
+ DEFAULT_CONFIG_DIRECTORY_PATH = 'lib/dbt'
16
+ DEFAULT_EXPORT_DIRECTORY_PATH = 'doc/dbt'
17
+
18
+ attr_writer :config_directory_path, :export_directory_path
19
+
20
+ def source_config_path
21
+ @source_config_path ||= "#{config_directory_path}/source_config.yml"
22
+ end
23
+
24
+ def source_config
25
+ @source_config ||= parse_yaml(source_config_path)
26
+ end
27
+
28
+ def source_name
29
+ @source_name ||= source_config.dig(:sources, :name).tap do |source_name|
30
+ raise SourceNameIsNullError, "'sources.name' is required in '#{source_config_path}'." if source_name.nil?
31
+ end
32
+ end
33
+
34
+ def config_directory_path
35
+ @config_directory_path ||= DEFAULT_CONFIG_DIRECTORY_PATH
36
+ end
37
+
38
+ def export_directory_path
39
+ @export_directory_path ||= DEFAULT_EXPORT_DIRECTORY_PATH
40
+ end
41
+
42
+ class SourceNameIsNullError < StandardError; end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Configuration
6
+ module DataSync
7
+ attr_writer :data_sync_delayed
8
+
9
+ def data_sync_delayed?
10
+ @data_sync_delayed ||= false
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Configuration
6
+ module Logger
7
+ DEFAULT_LOG_FILE_PATH = './log/active_record_dbt.log'
8
+ EXCLUDE_EXCEPTION_CLASS_NAMES = %w[ArInternalMetadatum SchemaMigration].freeze
9
+
10
+ attr_writer :logger
11
+
12
+ def logger
13
+ @logger ||= ::Logger.new(DEFAULT_LOG_FILE_PATH)
14
+ end
15
+
16
+ def add_log(class_name, exception)
17
+ return if include_exception_class_names?(exception)
18
+
19
+ logger.info(class_name) { format_log(exception) }
20
+ end
21
+
22
+ private
23
+
24
+ def include_exception_class_names?(exception)
25
+ exception.instance_of?(NameError) &&
26
+ EXCLUDE_EXCEPTION_CLASS_NAMES.include?(exception.name.to_s)
27
+ end
28
+
29
+ def format_log(exception)
30
+ {
31
+ exception: [
32
+ exception.class,
33
+ exception.message
34
+ ],
35
+ exception_backtrace: exception.backtrace.first(5)
36
+ }.to_json
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Configuration
6
+ module Parser
7
+ def parse_yaml(path)
8
+ return {} if path.nil?
9
+
10
+ YAML.load_file(path).with_indifferent_access || {}
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Configuration
6
+ module UsedDbtPackage
7
+ attr_writer :used_dbt_package_names
8
+
9
+ def used_dbt_utils?
10
+ used_dbt_package_names.include?('dbt-labs/dbt_utils')
11
+ end
12
+
13
+ def used_dbterd?
14
+ used_dbt_package_names.include?('datnguye/dbterd')
15
+ end
16
+
17
+ private
18
+
19
+ def used_dbt_package_names
20
+ @used_dbt_package_names ||= []
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module DbtPackage
6
+ module DbtUtils
7
+ module Table
8
+ module Testable
9
+ module UniqueCombinationOfColumnsTestable
10
+ REQUIRED_UNIQUE_COMBINATION_OF_COLUMNS_TESTABLE_METHODS = %i[table_name @config].freeze
11
+
12
+ delegate :used_dbt_utils?, to: :@config
13
+
14
+ REQUIRED_UNIQUE_COMBINATION_OF_COLUMNS_TESTABLE_METHODS.each do |method_name|
15
+ define_method(method_name) do
16
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
17
+ end
18
+ end
19
+
20
+ def unique_combination_of_columns_test
21
+ return nil unless used_dbt_utils?
22
+
23
+ ActiveRecord::Base.connection.indexes(table_name).each_with_object([]) do |index, array|
24
+ next if index.unique == false
25
+ next if (unique_indexes = index.columns).size == 1
26
+
27
+ array.push(
28
+ {
29
+ 'dbt_utils.unique_combination_of_columns' => {
30
+ 'combination_of_columns' => unique_indexes
31
+ }
32
+ }
33
+ )
34
+ end.presence
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module DbtPackage
6
+ module Dbterd
7
+ module Column
8
+ module Testable
9
+ module RelationshipsMetaRelationshipType
10
+ REQUIRED_RELATIONSHIP_TYPE_TESTABLE_METHODS = %i[@config foreign_key].freeze
11
+
12
+ delegate :used_dbterd?, :add_log, to: :@config
13
+
14
+ REQUIRED_RELATIONSHIP_TYPE_TESTABLE_METHODS.each do |method_name|
15
+ define_method(method_name) do
16
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
17
+ end
18
+ end
19
+
20
+ def relationships_meta_relationship_type
21
+ return nil unless used_dbterd?
22
+ return nil if foreign_key.nil? || relationship_type.blank?
23
+
24
+ {
25
+ 'relationship_type' => relationship_type
26
+ }
27
+ rescue NotSpecifiedOrNotInvalidIdError, StandardError => e
28
+ add_log(self.class, e)
29
+
30
+ {
31
+ 'relationship_type' => 'many-to-one',
32
+ 'active_record_dbt_error' => {
33
+ 'class' => e.class.to_s,
34
+ 'message' => e.message.to_s
35
+ }
36
+ }
37
+ end
38
+
39
+ private
40
+
41
+ # MEMO: It seems to be a good idea to set only 'many-to-one', 'one-to-one', and 'many-to-one'.
42
+ # * [Relationship Types - DaaC from dbt artifacts](https://dbterd.datnguyen.de/1.13/nav/metadata/relationship_type.html)
43
+ # * [Syntax | DBML](https://dbml.dbdiagram.io/docs/#relationships--foreign-key-definitions)
44
+ # * DBML supports 'one-to-many', 'many-to-one', 'one-to-one', and 'many-to-many'.
45
+ def relationship_type
46
+ # if one_to_many?
47
+ # 'one-to-many'
48
+ # elsif zero_to_many?
49
+ # 'zero-to-many'
50
+ # elsif many_to_many?
51
+ # 'many-to-many'
52
+ # elsif one_to_one?
53
+ if one_to_one?
54
+ 'one-to-one'
55
+ elsif many_to_one?
56
+ 'many-to-one'
57
+ else
58
+ raise NotSpecifiedOrNotInvalidIdError, 'Not specified/Invalid value'
59
+ end
60
+ end
61
+
62
+ # MEMO: If 'many-to-one' is specified, 'one-to-many' should not be necessary.
63
+ # def one_to_many?
64
+ # end
65
+
66
+ # MEMO:
67
+ # * It seems that `zero-to-many` cannot be specified in a dbt relationship.
68
+ # * The reverse may be possible, but cannot be specified in dbterd.
69
+ # * It doesn't look like it can be configured with dbml.
70
+ # * [Syntax | DBML](https://dbml.dbdiagram.io/docs/#relationships--foreign-key-definitions)
71
+ # def zero_to_many?
72
+ # end
73
+
74
+ # # TODO: Usually, there is always an intermediate table, so there is no `many-to-many`.
75
+ # def many_to_many?
76
+ # from_model_find_association_to_model?(:has_and_belongs_to_many) &&
77
+ # to_model_find_association_from_model?(:has_and_belongs_to_many)
78
+ # end
79
+
80
+ def one_to_one?
81
+ from_model_find_association_to_model?(:belongs_to) &&
82
+ to_model_find_association_from_model?(:has_one)
83
+ end
84
+
85
+ def many_to_one?
86
+ from_model_find_association_to_model?(:belongs_to) &&
87
+ to_model_find_association_from_model?(:has_many)
88
+ end
89
+
90
+ def to_model_find_association_from_model?(association_type)
91
+ to_model.reflect_on_all_associations(association_type).any? do |association|
92
+ association_klass(association) == from_model &&
93
+ association_foreign_key(association) == foreign_key_column
94
+ end
95
+ end
96
+
97
+ def from_model_find_association_to_model?(association_type)
98
+ from_model.reflect_on_all_associations(association_type).any? do |association|
99
+ association_klass(association) == to_model &&
100
+ association_foreign_key(association) == foreign_key_column
101
+ end
102
+ end
103
+
104
+ def association_klass(association)
105
+ association.klass
106
+ rescue NoMethodError
107
+ association.options.fetch(:through).to_s.classify.constantize
108
+ end
109
+
110
+ def association_foreign_key(association)
111
+ association.foreign_key
112
+ rescue NoMethodError
113
+ association.options.fetch(
114
+ :foreign_key,
115
+ "#{association.active_record.to_s.underscore}_id"
116
+ )
117
+ end
118
+
119
+ def foreign_key_column
120
+ foreign_key.dig(:options, :column)
121
+ end
122
+
123
+ def from_model
124
+ @from_model ||= foreign_key.from_table.classify.constantize
125
+ end
126
+
127
+ def to_model
128
+ @to_model ||= foreign_key.to_table.classify.constantize
129
+ end
130
+
131
+ class NotSpecifiedOrNotInvalidIdError < StandardError; end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Dbt
5
+ module Factory
6
+ module ColumnsFactory
7
+ def self.build(
8
+ table_name,
9
+ primary_keys: ActiveRecord::Base.connection.primary_keys(table_name),
10
+ foreign_keys: ActiveRecord::Base.connection.foreign_keys(table_name)
11
+ )
12
+ ActiveRecord::Base.connection.columns(table_name).map do |column|
13
+ column_test = ActiveRecord::Dbt::Column::Test.new(
14
+ table_name,
15
+ column,
16
+ primary_keys: primary_keys,
17
+ foreign_keys: foreign_keys
18
+ )
19
+
20
+ ActiveRecord::Dbt::Column::Column.new(
21
+ table_name,
22
+ column,
23
+ column_test,
24
+ primary_keys: primary_keys
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end