activerecord-dbt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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