k_domain 0.0.2 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +39 -1
  3. data/Gemfile +10 -0
  4. data/Rakefile +3 -1
  5. data/STORIES.md +21 -2
  6. data/k_domain.gemspec +4 -0
  7. data/lib/k_domain/domain_model/load.rb +35 -0
  8. data/lib/k_domain/domain_model/transform.rb +110 -0
  9. data/lib/k_domain/domain_model/transform_steps/_.rb +10 -0
  10. data/lib/k_domain/domain_model/transform_steps/step.rb +142 -0
  11. data/lib/k_domain/domain_model/transform_steps/step1_attach_db_schema.rb +21 -0
  12. data/lib/k_domain/domain_model/transform_steps/step2_attach_models.rb +62 -0
  13. data/lib/k_domain/domain_model/transform_steps/step3_attach_columns.rb +137 -0
  14. data/lib/k_domain/domain_model/transform_steps/step4_attach_erd_files.rb +456 -0
  15. data/lib/k_domain/domain_model/transform_steps/step5_attach_dictionary.rb +58 -0
  16. data/lib/k_domain/domain_model/transform_steps/step8_locate_rails_models.rb +44 -0
  17. data/lib/k_domain/raw_db_schema/load.rb +35 -0
  18. data/lib/k_domain/{raw_schema → raw_db_schema}/transform.rb +36 -21
  19. data/lib/k_domain/schemas/_.rb +15 -0
  20. data/lib/k_domain/schemas/database/_.rb +7 -0
  21. data/lib/k_domain/schemas/database/foreign_key.rb +14 -0
  22. data/lib/k_domain/schemas/database/index.rb +14 -0
  23. data/lib/k_domain/schemas/database/schema.rb +31 -0
  24. data/lib/k_domain/schemas/database/table.rb +32 -0
  25. data/lib/k_domain/schemas/dictionary.rb +19 -0
  26. data/lib/k_domain/schemas/domain/_.rb +65 -0
  27. data/lib/k_domain/schemas/domain/domain.rb +11 -0
  28. data/lib/k_domain/schemas/domain/erd_file.rb +80 -0
  29. data/lib/k_domain/schemas/domain/models/column.rb +49 -0
  30. data/lib/k_domain/schemas/domain/models/model.rb +111 -0
  31. data/lib/k_domain/schemas/domain/old/belongs_to.rb +25 -0
  32. data/lib/k_domain/schemas/domain/old/column_old.rb +225 -0
  33. data/lib/k_domain/schemas/domain/old/domain_statistics.rb +29 -0
  34. data/lib/k_domain/schemas/domain/old/entity.rb +338 -0
  35. data/lib/k_domain/schemas/domain/old/entity_statistics.rb +22 -0
  36. data/lib/k_domain/schemas/domain/old/foreign_key.rb +17 -0
  37. data/lib/k_domain/schemas/domain/old/has_and_belongs_to_many.rb +20 -0
  38. data/lib/k_domain/schemas/domain/old/has_many.rb +27 -0
  39. data/lib/k_domain/schemas/domain/old/has_one.rb +41 -0
  40. data/lib/k_domain/schemas/domain/old/name_options.rb +10 -0
  41. data/lib/k_domain/schemas/domain/old/rails_controller.rb +10 -0
  42. data/lib/k_domain/schemas/domain/old/rails_model.rb +92 -0
  43. data/lib/k_domain/schemas/domain/old/related_entity.rb +36 -0
  44. data/lib/k_domain/schemas/domain/old/statistics.rb +21 -0
  45. data/lib/k_domain/schemas/domain/old/validate.rb +25 -0
  46. data/lib/k_domain/schemas/domain/old/validates.rb +50 -0
  47. data/lib/k_domain/schemas/domain_model.rb +14 -0
  48. data/lib/k_domain/schemas/investigate.rb +15 -0
  49. data/lib/k_domain/schemas/rails_resource.rb +16 -0
  50. data/lib/k_domain/version.rb +1 -1
  51. data/lib/k_domain.rb +23 -1
  52. data/{lib/k_domain/raw_schema/template.rb → templates/load_schema.rb} +4 -4
  53. metadata +88 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a69b94955a43f91d71e034b94a5caf0d3fdbb7b130c480d4eabc45818bbe2262
4
- data.tar.gz: 0f4a126ee7c9bed5d99ac7449e5f97ec558030b126dbaa3c6194cdb5ce8430bd
3
+ metadata.gz: a50df0535cc32830a2035c2d2ddd328454efcef8aa97199485ae4db1dc7d64e7
4
+ data.tar.gz: 34824c4725142b76154a256d6466e7c83e8fc684178f6cb589552ea508d49dfa
5
5
  SHA512:
6
- metadata.gz: 3a7a877e80c9f23cdb93ab7952e027bdddc89bd6e888212c6fc0622cc0d5ae6d9b73e3e9651949ecd1afa2f1323e6446045f579cb6e83c030c5d8d711979deaa
7
- data.tar.gz: 434275e01ec2308d4a1407f5e8bd7ab9ec9708218510b6a719c144e2d9b6abb7e2caafa67efc617ac33295cd276c2326ccd961468ee4870b38266ef1b1295296
6
+ metadata.gz: 404ae56ada4ee46644d0c562b97dc86e9ce64164e25d1f66119399c4a053e41c183ff5c28184e5de493c76218bfb7f71ff548df02f9b374cb5d57b38c4ceaf3c
7
+ data.tar.gz: 27c472902e4ca2ea1dfb4803489cf5719356d02a2e64bfcee27ac0179bec5d42bb8c684cbf7196e77dd26a737f8c427bf4aa6809a3a7b930d19acaf269ab9247
data/.rubocop.yml CHANGED
@@ -6,12 +6,37 @@ AllCops:
6
6
  NewCops: enable
7
7
  Exclude:
8
8
  - "_/**/*"
9
- - "spec/samples/**/*"
9
+ - "spec/sample_input/**/*"
10
+ - "spec/sample_output/**/*"
11
+ - "lib/k_domain/raw_db_schema/template.rb"
12
+
13
+ Metrics/PerceivedComplexity:
14
+ Exclude:
15
+ - "lib/k_domain/domain_model/transform_steps/*.rb"
16
+ - "lib/k_domain/domain_model/dtos/entity.rb"
17
+ - "lib/k_domain/domain_model/dtos/old/entity.rb"
18
+
19
+ Metrics/AbcSize:
20
+ Exclude:
21
+ - "lib/k_domain/domain_model/transform_steps/*.rb"
22
+ - "lib/k_domain/domain_model/dtos/rails_model.rb"
23
+ - "lib/k_domain/domain_model/dtos/entity.rb"
24
+ - "lib/k_domain/domain_model/dtos/column_old.rb"
25
+ - "lib/k_domain/domain_model/dtos/old/column_old.rb"
26
+ - "lib/k_domain/domain_model/dtos/old/rails_model.rb"
27
+ - "lib/k_domain/domain_model/dtos/old/entity.rb"
28
+
29
+ Metrics/CyclomaticComplexity:
30
+ Exclude:
31
+ - "lib/k_domain/domain_model/transform_steps/*.rb"
32
+ - "lib/k_domain/domain_model/dtos/entity.rb"
33
+ - "lib/k_domain/domain_model/dtos/old/entity.rb"
10
34
 
11
35
  Metrics/BlockLength:
12
36
  Exclude:
13
37
  - "**/spec/**/*"
14
38
  - "*.gemspec"
39
+ - 'lib/k_domain/domain_model/dtos/erd_file.rb'
15
40
  IgnoredMethods:
16
41
  - configure
17
42
  - context
@@ -34,12 +59,19 @@ Metrics/BlockLength:
34
59
 
35
60
  Metrics/MethodLength:
36
61
  Max: 25
62
+ Exclude:
63
+ - "lib/k_domain/domain_model/transform_steps/*.rb"
64
+ - "lib/k_domain/domain_model/dtos/rails_model.rb"
65
+ - "lib/k_domain/domain_model/dtos/old/entity.rb"
66
+ - "lib/k_domain/domain_model/dtos/old/rails_model.rb"
37
67
 
38
68
  Layout/LineLength:
39
69
  Max: 200
40
70
  # Ignores annotate output
41
71
  IgnoredPatterns: ['\A# \*\*']
42
72
  IgnoreCopDirectives: true
73
+ Exclude:
74
+ - "lib/k_domain/domain_model/transform_steps/*.rb"
43
75
 
44
76
  Lint/UnusedMethodArgument:
45
77
  AllowUnusedKeywordArguments: true
@@ -77,6 +109,12 @@ Lint/AmbiguousBlockAssociation:
77
109
  Style/AccessorGrouping:
78
110
  Enabled: false
79
111
 
112
+ Style/FormatStringToken:
113
+ Enabled: false
114
+
115
+ Style/Documentation:
116
+ Enabled: false
117
+
80
118
  Layout/SpaceBeforeComma:
81
119
  Enabled: false
82
120
  # My Preferences - End
data/Gemfile CHANGED
@@ -23,3 +23,13 @@ group :development, :test do
23
23
  gem 'rubocop-rake', require: false
24
24
  gem 'rubocop-rspec', require: false
25
25
  end
26
+
27
+ # If local dependency
28
+ if ENV['KLUE_LOCAL_GEMS']&.to_s&.downcase == 'true'
29
+ group :development, :test do
30
+ puts 'Using Local GEMs'
31
+ gem 'peeky' , path: '../peeky'
32
+ gem 'k_log' , path: '../k_log'
33
+ gem 'k_util' , path: '../k_util'
34
+ end
35
+ end
data/Rakefile CHANGED
@@ -26,7 +26,9 @@ task :publish do
26
26
  system 'gem build'
27
27
  system "gem push #{GEM_NAME}-#{KDomain::VERSION}.gem"
28
28
  end
29
-
29
+ task :build do
30
+ system 'gem build'
31
+ end
30
32
  desc 'Remove old *.gem files'
31
33
  task :clean do
32
34
  system 'rm *.gem'
data/STORIES.md CHANGED
@@ -8,9 +8,28 @@ As an Application Developer, I need a rich and configurable ERD schema, so I can
8
8
 
9
9
  ### Stories next on list
10
10
 
11
- As a Developer, I can DO_SOMETHING, so that I QUALITY_OF_LIFE
11
+ As a Developer, I can print any of the domain structures, so that I can visually my domain
12
12
 
13
- - Subtask
13
+ - Hook up log.structure
14
+
15
+ As a Developer, I can customize domain configuration, so that I can have opinions about names and types
16
+
17
+ - Handle traits
18
+
19
+ As a Developer, I can read native rails model data, so that I can leverage existing rails applications for ERD modeling
20
+
21
+ - Use Meta Programming and re-implement ActiveRecord::Base
22
+
23
+ ### Tasks next on list
24
+
25
+ Refactor / Simply
26
+
27
+ - Replace complex objects an with structs for ancillary data structures such as investigate
28
+
29
+ User acceptance testing
30
+
31
+ - Provide sample printers for each data structure to visually check data is loading
32
+ - Point raw_db_schema loader towards a complex ERD and check how it performs
14
33
 
15
34
  ## Stories and tasks
16
35
 
data/k_domain.gemspec CHANGED
@@ -33,10 +33,14 @@ Gem::Specification.new do |spec|
33
33
  f.match(%r{^(test|spec|features)/})
34
34
  end
35
35
  end
36
+
36
37
  spec.bindir = 'exe'
37
38
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
39
  spec.require_paths = ['lib']
39
40
  # spec.extensions = ['ext/k_domain/extconf.rb']
40
41
 
42
+ spec.add_dependency 'activesupport' , '~> 6'
43
+ spec.add_dependency 'dry-struct', '~> 1'
41
44
  spec.add_dependency 'k_log' , '~> 0.0.0'
45
+ spec.add_dependency 'peeky' , '~> 0.0.0'
42
46
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Annotates the original schema with methods that implement existing method calls
4
+ # that are already in the schema so that we can build a hash.
5
+ #
6
+ # Writes a new annotated schema.rb file with a public method called load that
7
+ # builds the hash
8
+
9
+ module KDomain
10
+ module DomainModel
11
+ class Load
12
+ include KLog::Logging
13
+
14
+ attr_reader :source_file
15
+ attr_reader :data
16
+
17
+ def initialize(source_file)
18
+ @source_file = source_file
19
+ end
20
+
21
+ def call
22
+ json = File.read(source_file)
23
+ @raw_data = KUtil.data.json_parse(json, as: :hash_symbolized)
24
+
25
+ @data = KDomain::Schemas::DomainModel.new(@raw_data)
26
+ end
27
+
28
+ def to_h
29
+ return nil unless defined? @raw_data
30
+
31
+ @raw_data
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loads the db schema object and works through a series of enrichment steps to
4
+ # that builds the domain modal
5
+
6
+ module KDomain
7
+ module DomainModel
8
+ class Transform
9
+ include KLog::Logging
10
+
11
+ attr_reader :db_schema
12
+ attr_reader :target_step_file
13
+ attr_reader :target_file
14
+ attr_reader :erd_path
15
+
16
+ def initialize(db_schema: , target_file: , target_step_file: , erd_path:)
17
+ @db_schema = db_schema
18
+ @target_step_file = target_step_file
19
+ @target_file = target_file
20
+ @erd_path = erd_path
21
+ end
22
+
23
+ def call
24
+ valid = true
25
+ valid &&= step1
26
+ valid &&= step2
27
+ valid &&= step3
28
+ valid &&= step4
29
+ valid &&= step5
30
+ valid &&= step8 # NOT SURE WHERE THIS BELONGS
31
+
32
+ raise 'DomainModal transform failed' unless valid
33
+
34
+ write
35
+
36
+ nil
37
+ end
38
+
39
+ def step1
40
+ Step1AttachDbSchema.run(domain_data, db_schema: db_schema)
41
+ write(step: '1-attach-db-schema')
42
+ end
43
+
44
+ def step2
45
+ Step2AttachModels.run(domain_data, erd_path: erd_path)
46
+ write(step: '2-attach-model')
47
+ end
48
+
49
+ def step3
50
+ Step3AttachColumns.run(domain_data)
51
+ write(step: '3-attach-columns')
52
+ end
53
+
54
+ def step4
55
+ Step4AttachErdFiles.run(domain_data, erd_path: erd_path)
56
+ write(step: '4-attach-erd-files')
57
+ end
58
+
59
+ def step5
60
+ Step5AttachDictionary.run(domain_data, erd_path: erd_path)
61
+ write(step: '5-attach-dictionary')
62
+ end
63
+
64
+ def step8
65
+ Step8LocateRailsModels.run(domain_data, erd_path: erd_path)
66
+ write(step: '8-rails-files-models')
67
+ end
68
+
69
+ def write(step: nil)
70
+ file = if step.nil?
71
+ target_file
72
+ else
73
+ format(target_step_file, step: step)
74
+ end
75
+ FileUtils.mkdir_p(File.dirname(file))
76
+ File.write(file, JSON.pretty_generate(domain_data))
77
+ end
78
+
79
+ def domain_data
80
+ # The initial domain model structure is created here, but populated during the workflows.
81
+ @domain_data ||= {
82
+ domain: {
83
+ models: [],
84
+ erd_files: [],
85
+ },
86
+ rails: {
87
+ models: [],
88
+ controllers: [],
89
+ },
90
+ rails_resource: {
91
+ models: [],
92
+ controllers: [],
93
+ },
94
+ dictionary: {
95
+ items: []
96
+ },
97
+ database: {
98
+ tables: [],
99
+ indexes: [],
100
+ foreign_keys: [],
101
+ meta: {}
102
+ },
103
+ investigate: {
104
+ issues: []
105
+ }
106
+ }
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The require order is important due to dependencies
4
+ require_relative './step'
5
+ require_relative './step1_attach_db_schema'
6
+ require_relative './step2_attach_models'
7
+ require_relative './step3_attach_columns'
8
+ require_relative './step4_attach_erd_files'
9
+ require_relative './step5_attach_dictionary'
10
+ require_relative './step8_locate_rails_models'
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDomain
4
+ module DomainModel
5
+ class Step
6
+ include KLog::Logging
7
+
8
+ attr_reader :domain_data
9
+ attr_reader :opts
10
+ attr_reader :valid
11
+ alias valid? valid
12
+
13
+ def initialize(domain_data, **opts)
14
+ # Useful for debugging
15
+ # log.info "Initialize #{self.class.name}"
16
+
17
+ @domain_data = domain_data
18
+ @opts = opts
19
+ @valid = true
20
+ end
21
+
22
+ def call; end
23
+
24
+ def self.run(domain_data, **opts)
25
+ step = new(domain_data, **opts)
26
+ step.call
27
+ step
28
+ end
29
+
30
+ def guard(message)
31
+ log.error message
32
+ @valid = false
33
+ end
34
+
35
+ # Domain Model Accessor/Helpers
36
+ def domain
37
+ guard('domain is missing') if domain_data[:domain].nil?
38
+
39
+ domain_data[:domain]
40
+ end
41
+
42
+ def domain_models
43
+ domain[:models]
44
+ end
45
+
46
+ # Rails File Accessor/Helpers
47
+ def rails_resource
48
+ guard('rails_resource is missing') if domain_data[:rails_resource].nil?
49
+
50
+ domain_data[:rails_resource]
51
+ end
52
+
53
+ def rails_resource_models
54
+ rails_resource[:models]
55
+ end
56
+
57
+ def rails_resource_models=(value)
58
+ rails_resource[:models] = value
59
+ end
60
+
61
+ def rails_resource_controllers
62
+ rails_resource[:controllers]
63
+ end
64
+
65
+ # Database Accessor/Helpers
66
+ def database=(value)
67
+ domain_data[:database] = value
68
+ end
69
+
70
+ def database
71
+ guard('database is missing') if domain_data[:database].nil?
72
+
73
+ domain_data[:database]
74
+ end
75
+
76
+ def database_tables
77
+ guard('database_tables is missing') if database[:tables].nil?
78
+
79
+ database[:tables]
80
+ end
81
+
82
+ def database_foreign_keys
83
+ guard('database_foreign_keys is missing') if database[:foreign_keys].nil?
84
+
85
+ database[:foreign_keys]
86
+ end
87
+
88
+ def find_table_for_model(model)
89
+ database_tables.find { |table| table[:name] == model[:table_name] }
90
+ end
91
+
92
+ def table_name_exist?(table_name)
93
+ if table_name.nil?
94
+ guard('table_name_exist? was provided with a table_name: nil')
95
+ return false
96
+ end
97
+ database_table_name_hash.key?(table_name)
98
+ end
99
+
100
+ def find_foreign_table(lhs_table_name, column_name)
101
+ fk = database_foreign_keys.find { |foreign_key| foreign_key[:left] == lhs_table_name && foreign_key[:column] == column_name }
102
+ return fk[:right] if fk
103
+
104
+ nil
105
+ end
106
+
107
+ def investigate(step:, location:, key:, message:)
108
+ unique_key = build_key(step, location, key)
109
+
110
+ return if issue_hash.key?(unique_key)
111
+
112
+ value = { step: step, location: location, key: key, message: message }
113
+
114
+ issues << value # list
115
+ issue_hash[unique_key] = value # lookup
116
+ end
117
+
118
+ def issues
119
+ domain_data[:investigate][:issues]
120
+ end
121
+
122
+ private
123
+
124
+ def database_table_name_hash
125
+ @database_table_name_hash ||= database_tables.to_h { |table| [table[:name], table[:name]] }
126
+ end
127
+
128
+ def build_key(*values)
129
+ values.join('-')
130
+ end
131
+
132
+ def issue_hash
133
+ return @issue_hash if defined? @issue_hash
134
+
135
+ @issue_hash = issues.to_h do |issue|
136
+ unique_key = build_key(issue[:step], issue[:location], issue[:key])
137
+ [unique_key, issue]
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDomain
4
+ module DomainModel
5
+ class Step1AttachDbSchema < KDomain::DomainModel::Step
6
+ # Map database schema to domain model
7
+ def call
8
+ raise 'Schema not supplied' if opts[:db_schema].nil?
9
+
10
+ self.database = opts[:db_schema].clone
11
+
12
+ guard('tables are missing') if database[:tables].nil?
13
+ guard('indexes are missing') if database[:indexes].nil?
14
+ guard('foreign keys are missing') if database[:foreign_keys].nil?
15
+ guard('rails version is missing') if database[:meta][:rails].nil?
16
+ guard('postgres extensions are missing') if database[:meta][:db_info][:extensions].nil?
17
+ guard('unique keys are missing') if database[:meta][:unique_keys].nil?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loop through the db_schema tables and build up a
4
+ # basic model for each table
5
+ class Step2AttachModels < KDomain::DomainModel::Step
6
+ # Map database schema to domain model
7
+ def call
8
+ raise 'ERD path not supplied' if opts[:erd_path].nil?
9
+
10
+ # Schema is re-shaped into a format designed for domain modeling
11
+ domain[:models] = database_tables.map { |table| model(table) }
12
+ end
13
+
14
+ def model(table)
15
+ table_name = table[:name].to_s
16
+ model_name = table_name.singularize
17
+
18
+ {
19
+ name: model_name,
20
+ name_plural: table_name, # need to check if this is correct as I know it is wrong for account_history_datum
21
+ table_name: table_name,
22
+ pk: primary_key(table),
23
+ erd_location: location(table_name, model_name),
24
+ statistics: {}, # Load in future step
25
+ columns: [] # Load in future step
26
+ }
27
+ end
28
+
29
+ def primary_key(table)
30
+ {
31
+ name: table[:primary_key],
32
+ type: table[:primary_key_type],
33
+ exist: !table[:primary_key].nil?
34
+ }
35
+ end
36
+
37
+ # Location of source code
38
+ def location(table_name, model_name)
39
+ file_normal = File.join(opts[:erd_path], "#{model_name}.rb")
40
+ file_custom = File.join(opts[:erd_path], "#{table_name}.rb")
41
+ file_exist = true
42
+ state = []
43
+
44
+ if File.exist?(file_normal)
45
+ file = file_normal
46
+ state.push(:has_ruby_model)
47
+ elsif File.exist?(file_custom)
48
+ file = file_custom
49
+ state.push(:has_ruby_model)
50
+ state.push(:nonconventional_name)
51
+ else
52
+ file = ''
53
+ file_exist = false
54
+ end
55
+
56
+ {
57
+ file: file,
58
+ exist: file_exist,
59
+ state: state # display_state: state.join(' ')
60
+ }
61
+ end
62
+ end
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Attach columns to models
4
+ class Step3AttachColumns < KDomain::DomainModel::Step
5
+ attr_accessor :table
6
+ attr_reader :column_name
7
+ attr_reader :column_symbol
8
+
9
+ def call
10
+ build_columns
11
+ end
12
+
13
+ def build_columns
14
+ domain_models.each do |model|
15
+ @table = find_table_for_model(model)
16
+ columns = columns(table[:columns])
17
+ columns = insert_primary_key(model, columns)
18
+ model[:columns] = columns
19
+ end
20
+ end
21
+
22
+ def column_data(name)
23
+ @column_name = name
24
+ @column_symbol = name.to_sym
25
+ {
26
+ name: name,
27
+ name_plural: name.pluralize,
28
+ type: nil,
29
+ precision: nil,
30
+ scale: nil,
31
+ default: nil,
32
+ null: nil,
33
+ limit: nil,
34
+ array: nil
35
+ }
36
+ end
37
+
38
+ def columns(db_columns)
39
+ db_columns.map do |db_column|
40
+ column = column_data(db_column[:name]).merge(
41
+ type: check_type(db_column[:type]),
42
+ precision: db_column[:precision],
43
+ scale: db_column[:scale],
44
+ default: db_column[:default],
45
+ null: db_column[:null],
46
+ limit: db_column[:limit],
47
+ array: db_column[:array]
48
+ )
49
+
50
+ expand_column(column)
51
+ end
52
+ end
53
+
54
+ def insert_primary_key(model, columns)
55
+ return columns unless model[:pk][:exist]
56
+
57
+ column = column_data('id').merge(
58
+ type: check_type(model[:pk][:type])
59
+ )
60
+
61
+ columns.unshift(expand_column(column))
62
+ columns
63
+ end
64
+
65
+ def expand_column(column)
66
+ foreign_table = lookup_foreign_table(column_name)
67
+ is_foreign = !foreign_table.nil?
68
+ # is_foreign = foreign_key?(column_name)
69
+ structure_type = structure_type(is_foreign)
70
+
71
+ column.merge({
72
+ structure_type: structure_type,
73
+ foreign_key: is_foreign,
74
+ foreign_table: (foreign_table || '').singularize,
75
+ foreign_table_plural: (foreign_table || '').pluralize
76
+ })
77
+ end
78
+
79
+ def check_type(type)
80
+ type = type.to_sym if type.is_a?(String)
81
+
82
+ return type if %i[string integer bigint bigserial boolean float decimal datetime date hstore text jsonb].include?(type)
83
+
84
+ if type.nil?
85
+ guard('nil type detected for db_column[:type]')
86
+
87
+ return :string
88
+ end
89
+
90
+ guard("new type detected for db_column[:type] - #{type}")
91
+
92
+ camel.parse(type.to_s).downcase
93
+ end
94
+
95
+ def lookup_foreign_table(column_name)
96
+ foreign_table = find_foreign_table(table[:name], column_name)
97
+
98
+ return foreign_table if foreign_table
99
+
100
+ cn = column_name.to_s
101
+
102
+ if cn.ends_with?('_id')
103
+ table_name = column_name[0..-4]
104
+ table_name_plural = table_name.pluralize
105
+
106
+ if table_name_exist?(table_name_plural.to_s)
107
+ investigate(step: :step3_attach_columns,
108
+ location: :lookup_foreign_table,
109
+ key: column_name,
110
+ message: "#{@table[:name]}.#{column_name} => #{table_name_plural} - Relationship not found in DB, so have inferred this relationship. You may want to check that this relation is correct")
111
+
112
+ return table_name
113
+ end
114
+
115
+ investigate(step: :step3_attach_columns,
116
+ location: :lookup_foreign_table,
117
+ key: column_name,
118
+ message: "#{@table[:name]}.#{column_name} => #{table_name_plural} - Table not found for a column that looks like foreign_key")
119
+ end
120
+
121
+ nil
122
+ end
123
+
124
+ # Need some configurable data dictionary where by
125
+ # _token can be setup on a project by project basis
126
+ def structure_type(is_foreign)
127
+ return :foreign_key if is_foreign
128
+ return :primary_key if column_symbol == :id
129
+ return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
130
+ return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
131
+ return :deleted_at if column_symbol == :deleted_at
132
+ return :encrypted_password if column_symbol == :encrypted_password
133
+ return :token if column_name.ends_with?('_token') || column_name.ends_with?('_token_iv')
134
+
135
+ :data
136
+ end
137
+ end