k_domain 0.0.23 → 0.0.28

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 +4 -4
  2. data/.builders/boot.rb +40 -0
  3. data/.builders/generators/configuration_generator.rb +22 -0
  4. data/.builders/run.rb +16 -0
  5. data/.github/workflows/main.yml +5 -3
  6. data/.gitignore +1 -0
  7. data/.rubocop.yml +8 -3
  8. data/Gemfile +2 -2
  9. data/k_domain.gemspec +1 -1
  10. data/lib/k_domain/config/_.rb +4 -0
  11. data/lib/k_domain/config/config.rb +19 -0
  12. data/lib/k_domain/config/configuration.rb +76 -0
  13. data/lib/k_domain/domain_model/build_rich_models.rb +83 -0
  14. data/lib/k_domain/domain_model/load.rb +44 -1
  15. data/lib/k_domain/domain_model/transform.rb +13 -11
  16. data/lib/k_domain/domain_model/transform_steps/step1_db_schema.rb +1 -1
  17. data/lib/k_domain/domain_model/transform_steps/step2_domain_models.rb +1 -1
  18. data/lib/k_domain/domain_model/transform_steps/step6_rails_structure_models.rb +1 -0
  19. data/lib/k_domain/domain_model/transform_steps/step7_rails_structure_controllers.rb +8 -3
  20. data/lib/k_domain/domain_model/transform_steps/step8_domain_columns.rb +51 -56
  21. data/lib/k_domain/queries/_.rb +4 -0
  22. data/lib/k_domain/queries/base_query.rb +13 -0
  23. data/lib/k_domain/queries/domain_model_query.rb +88 -0
  24. data/lib/k_domain/rails_code_extractor/extract_controller.rb +2 -0
  25. data/lib/k_domain/rails_code_extractor/extract_model.rb +2 -0
  26. data/lib/k_domain/rails_code_extractor/shim_loader.rb +4 -2
  27. data/lib/k_domain/raw_db_schema/transform.rb +26 -2
  28. data/lib/k_domain/schemas/_.rb +3 -1
  29. data/lib/k_domain/schemas/domain/erd_file.rb +78 -77
  30. data/lib/k_domain/schemas/domain.rb +79 -38
  31. data/lib/k_domain/schemas/{domain/_.rb → domain_types.rb} +1 -8
  32. data/lib/k_domain/schemas/{domain_model.rb → main_dataset.rb} +2 -2
  33. data/lib/k_domain/schemas/rails_structure.rb +10 -0
  34. data/lib/k_domain/version.rb +1 -1
  35. data/lib/k_domain.rb +6 -1
  36. data/templates/custom/action_controller.rb +0 -29
  37. data/templates/custom/controller_interceptors.rb +9 -7
  38. data/templates/custom/model_interceptors.rb +48 -3
  39. data/templates/rails/active_record.rb +2 -0
  40. data/templates/sample_config.rb +47 -0
  41. metadata +17 -10
  42. data/.builders/config/_.rb +0 -3
  43. data/.builders/setup.rb +0 -30
  44. data/templates/old_printspeek_schema copy.rb +0 -231
  45. data/templates/old_printspeek_schema.rb +0 -233
@@ -9,15 +9,15 @@ class Step8DomainColumns < KDomain::DomainModel::Step
9
9
  attr_reader :column_symbol
10
10
 
11
11
  def call
12
+ @debug = true
12
13
  enrich_columns
13
14
  end
14
15
 
15
16
  def enrich_columns
16
17
  # .select {|m| m[:name] == 'app_user'}
17
18
  domain_models.each do |model|
18
- @domain_model = model
19
+ @domain_model = enrich_model(model)
19
20
  # this will be nil if there is no rails model code
20
- @rails_model = find_rails_structure_models(domain_model[:name])
21
21
 
22
22
  # log.warn domain_model[:name]
23
23
  domain_model[:columns].each do |column|
@@ -25,75 +25,29 @@ class Step8DomainColumns < KDomain::DomainModel::Step
25
25
  @column_name = column[:name]
26
26
  @column_symbol = column[:name].to_sym
27
27
 
28
- attach_foreign_key
29
28
  column[:structure_type] = structure_type
30
29
  end
31
30
  end
32
31
  end
33
32
 
34
- def expand_column(column)
35
- foreign_table = lookup_foreign_table(column_name)
36
- is_foreign = !foreign_table.nil?
37
- # is_foreign = foreign_key?(column_name)
38
- structure_type = structure_type(is_foreign)
39
-
40
- column.merge({
41
- structure_type: structure_type,
42
- foreign_key: is_foreign,
43
- foreign_table: (foreign_table || '').singularize,
44
- foreign_table_plural: (foreign_table || '').pluralize
45
- })
46
- end
47
-
48
- def lookup_foreign_table(column_name)
49
- foreign_table = find_foreign_table(table[:name], column_name)
50
-
51
- return foreign_table if foreign_table
52
-
53
- cn = column_name.to_s
54
-
55
- if cn.ends_with?('_id')
56
- table_name = column_name[0..-4]
57
- table_name_plural = table_name.pluralize
58
-
59
- if table_name_exist?(table_name_plural.to_s)
60
- investigate(step: :step8_columns,
61
- location: :lookup_foreign_table,
62
- key: column_name,
63
- 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")
64
-
65
- return table_name
66
- end
67
-
68
- investigate(step: :step8_columns,
69
- location: :lookup_foreign_table,
70
- key: column_name,
71
- message: "#{@table[:name]}.#{column_name} => #{table_name_plural} - Table not found for a column that looks like foreign_key")
72
- end
73
-
74
- nil
75
- end
33
+ def enrich_model(model)
34
+ # NOTE: THIS MAY GET MOVED TO DomainModel::Load#enrichment
35
+ @rails_model = find_rails_structure_models(model[:name])
76
36
 
77
- def attach_foreign_key
78
- return if rails_model.nil? || rails_model[:behaviours].nil? || rails_model[:behaviours][:belongs_to].nil?
37
+ model[:file] = @rails_model[:file]
79
38
 
80
- foreign = rails_model[:behaviours][:belongs_to].find { |belong| belong[:opts][:foreign_key].to_sym == domain_column[:name].to_sym }
39
+ log.error "Rails model not found for: #{model[:name]}" unless @rails_model
81
40
 
82
- return unless foreign
83
-
84
- # NEED TO PRE-LOAD the table, table_plural and model
85
- domain_column[:foreign_table] = 'xxx1'
86
- domain_column[:foreign_table_plural] = 'xxx3'
87
- domain_column[:foreign_model] = 'xxx2'
41
+ model
88
42
  end
89
43
 
90
44
  # Need some configurable data dictionary where by
91
45
  # _token can be setup on a project by project basis
92
46
  def structure_type
93
47
  return :primary_key if domain_model[:pk][:name] == column_name
94
- return :foreign_key if domain_column[:foreign_table]
48
+ return :foreign_key if foreign_relationship?
49
+ return :foreign_type if column_symbol == :context_type || column_symbol == :element_type
95
50
 
96
- return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
97
51
  return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
98
52
  return :deleted_at if column_symbol == :deleted_at
99
53
  return :encrypted_password if column_symbol == :encrypted_password
@@ -101,4 +55,45 @@ class Step8DomainColumns < KDomain::DomainModel::Step
101
55
 
102
56
  :data
103
57
  end
58
+
59
+ def foreign_relationship?
60
+ return false if rails_model.nil? || rails_model[:behaviours].nil? || rails_model[:behaviours][:belongs_to].nil?
61
+
62
+ column_name = domain_column[:name].to_sym
63
+ rails_model[:behaviours][:belongs_to].any? { |belong| belong[:opts][:foreign_key].to_sym == column_name }
64
+ end
65
+
66
+ # def attach_relationships
67
+ # domain_column[:relationships] = []
68
+ # return if rails_model.nil? || rails_model[:behaviours].nil? || rails_model[:behaviours][:belongs_to].nil?
69
+
70
+ # column_name = domain_column[:name].to_sym
71
+
72
+ # attach_column_relationships(column_name)
73
+ # end
74
+
75
+ # def select_belongs_to(column_name)
76
+ # rails_model[:behaviours][:belongs_to].select { |belong| belong[:opts][:foreign_key].to_sym == column_name.to_sym }
77
+ # end
78
+
79
+ # # this just maps basic relationship information,
80
+ # # to go deeper you really need to use the Rails Model Behaviours
81
+ # def attach_column_relationships(column_name)
82
+ # select_belongs_to(column_name).each do |belongs_to|
83
+ # domain_column[:relationships] << map_belongs_to(belongs_to)
84
+ # end
85
+ # end
86
+
87
+ # def map_belongs_to(belongs_to)
88
+ # @domain_column[:structure_type] = :foreign_key
89
+ # # result = {
90
+ # # type: :belongs_to,
91
+ # # name: belongs_to[:name],
92
+ # # foreign_key: belongs_to.dig(:opts, :foreign_key) || @domain_column[:name],
93
+ # # }
94
+
95
+ # # result[:primary_key] = belongs_to.dig(:opts, :primary_key) if belongs_to.dig(:opts, :primary_key)
96
+ # # result[:class_name] = belongs_to.dig(:opts, :class_name) if belongs_to.dig(:opts, :class_name)
97
+ # result
98
+ # end
104
99
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './base_query'
4
+ require_relative './domain_model_query'
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDomain
4
+ module Queries
5
+ class BaseQuery
6
+ attr_reader :domain_model
7
+
8
+ def initialize(domain_model)
9
+ @domain_model = domain_model
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDomain
4
+ module Queries
5
+ # Query models found on the domain model
6
+ # by
7
+ # has ruby file
8
+ # has primary key
9
+ # column count
10
+ # data column count
11
+ # foreign key column count
12
+ # has timestamp (created_at, updated_at) columns
13
+ # has created_at
14
+ # has updated_at
15
+ # has deleted_at
16
+ # has polymorphic foreign keys
17
+ # has virtual columns
18
+ # virtual column filters (token, encrypted_password, etc)
19
+ class DomainModelQuery < BaseQuery
20
+ def all
21
+ domain_model.domain.models
22
+ end
23
+
24
+ def query(**filters)
25
+ @query = all.clone
26
+
27
+ filters.each do |key, value|
28
+ send("filter_#{key}", value)
29
+ end
30
+
31
+ @query
32
+ end
33
+
34
+ private
35
+
36
+ def filter_ruby(value)
37
+ @query.select! { |model| model.ruby? == value }
38
+ end
39
+
40
+ def filter_pk(value)
41
+ @query.select! { |model| model.pk.exist? == value }
42
+ end
43
+
44
+ def filter_column_count(block)
45
+ @query.select! { |model| block.call(model.columns.count) }
46
+ end
47
+
48
+ def filter_data_column_count(block)
49
+ @query.select! { |model| block.call(model.columns_data.count) }
50
+ end
51
+
52
+ def filter_foreign_key_column_count(block)
53
+ @query.select! { |model| block.call(model.columns_foreign_key.count) }
54
+ end
55
+ alias filter_fk_column_count filter_foreign_key_column_count
56
+ alias filter_fk_count filter_foreign_key_column_count
57
+
58
+ def filter_polymorphic_foreign_key_column_count(block)
59
+ @query.select! { |model| block.call(model.columns_foreign_type.count) }
60
+ end
61
+ alias filter_poly_fk_column_count filter_polymorphic_foreign_key_column_count
62
+ alias filter_poly_fk_count filter_polymorphic_foreign_key_column_count
63
+
64
+ def filter_timestamp(value)
65
+ @query.select! { |model| (model.columns_timestamp.count == 2) == value }
66
+ end
67
+
68
+ def filter_created_at(value)
69
+ @query.select! { |model| (model.columns.any? { |column| column.name == 'created_at' } == value) }
70
+ end
71
+
72
+ def filter_updated_at(value)
73
+ @query.select! { |model| (model.columns.any? { |column| column.name == 'updated_at' } == value) }
74
+ end
75
+
76
+ def filter_deleted_at(value)
77
+ @query.select! { |model| (model.columns.any? { |column| column.name == 'deleted_at' } == value) }
78
+ end
79
+ # has virtual columns
80
+ # virtual column filters (token, encrypted_password, etc)
81
+
82
+ # # HELP: this filter affects table rows, eg. if a table has less the 2 columns then include the table
83
+ # low_column: -> (model) { model.columns.length < 5 },
84
+ # suspected_m2m: -> (model) { model.columns_foreign.length == 2 && model.columns_data.length < 3 },
85
+ # invalid_types: -> (model) { model.columns.any? { |c| [c.db_type, c.csharp_type, c.ruby_type].include?('******') } },
86
+ end
87
+ end
88
+ end
@@ -48,9 +48,11 @@ module KDomain
48
48
  # puts e.message
49
49
  if e.is_a?(NameError) && e.message != last_error&.message
50
50
  log.kv('add module', e.name)
51
+ log.kv 'file', file
51
52
  eval("module #{e.name}; end")
52
53
  return load_retry(file, times - 1, e)
53
54
  end
55
+ log.kv 'file', file
54
56
  log.exception(e, style: :short, method_info: method(__callee__))
55
57
  end
56
58
  # rubocop:enable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
@@ -58,9 +58,11 @@ module KDomain
58
58
  # puts e.message
59
59
  if e.is_a?(NameError) && e.message != last_error&.message
60
60
  log.kv('add module', e.name)
61
+ log.kv 'file', file
61
62
  eval("module #{e.name}; end")
62
63
  return load_retry(file, times - 1, e)
63
64
  end
65
+ log.kv 'file', file
64
66
  log.exception(e, style: :short, method_info: method(__callee__))
65
67
  end
66
68
  # rubocop:enable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
@@ -18,8 +18,10 @@ module KDomain
18
18
  end
19
19
 
20
20
  def call
21
- # puts shim_files.map { |sf| sf[:file] }
22
- shim_files.select { |sf| sf[:exist] }.each { |sf| require sf[:file] }
21
+ shim_files.select { |sf| sf[:exist] }.each do |sf|
22
+ require sf[:file]
23
+ end
24
+ nil
23
25
  end
24
26
 
25
27
  def register(name, file)
@@ -7,16 +7,29 @@
7
7
  # builds the hash
8
8
  module KDomain
9
9
  module RawDbSchema
10
+ # class TransformFilter
11
+ # attr_accessor :take
12
+ # def initialize(take: :all)
13
+ # @take = take
14
+ # end
15
+ # end
16
+
10
17
  class Transform
11
18
  include KLog::Logging
12
19
 
13
20
  attr_reader :source_file
14
21
  attr_accessor :template_file
15
22
  attr_reader :schema_loader
23
+ attr_reader :filter
16
24
 
17
- def initialize(source_file)
25
+ # @param [String] source_file Rails Schema file
26
+ # @param [OpenStruct] filter Settings for filtering data before transformation, this is useful during debugging
27
+ # examples
28
+ # filter = os(run: 1, tables: os(offset: 10, limit: 10))
29
+ def initialize(source_file, filter)
18
30
  @source_file = source_file
19
31
  @template_file = KDomain::Gem.resource('templates/load_schema.rb')
32
+ @filter = filter
20
33
  end
21
34
 
22
35
  def call
@@ -73,11 +86,22 @@ module KDomain
73
86
 
74
87
  loader = LoadSchema.new
75
88
  loader.load_schema
76
- loader.schema
89
+
90
+ apply_filter(loader.schema)
77
91
  rescue StandardError => e
78
92
  log.exception(e)
79
93
  end
80
94
  # rubocop:enable Security/Eval
95
+
96
+ # rubocop:disable Metrics/AbcSize
97
+ def apply_filter(schema)
98
+ return schema unless filter.active == 1
99
+
100
+ schema[:tables] = schema[:tables].slice(filter.table.offset, filter.table.limit) || [] if filter.table.offset.is_a?(Integer) && filter.table.limit.is_a?(Integer)
101
+
102
+ schema
103
+ end
104
+ # rubocop:enable Metrics/AbcSize
81
105
  end
82
106
  end
83
107
  end
@@ -11,6 +11,8 @@ require_relative 'rails_structure'
11
11
  require_relative 'investigate'
12
12
  require_relative 'database'
13
13
  require_relative 'dictionary'
14
+ require_relative 'domain_types'
14
15
  require_relative 'domain'
16
+ require_relative 'main_dataset'
15
17
 
16
- require_relative './domain_model'
18
+ # require_relative './domain_model'
@@ -1,82 +1,83 @@
1
1
  # frozen_string_literal: true
2
+ # # frozen_string_literal: true
2
3
 
3
- # Domain class holds a list of the entities
4
- module KDomain
5
- module DomainModel
6
- # rubocop:disable Metrics/BlockLength
7
- class ErdFile < Dry::Struct
8
- attribute :name , Types::Strict::String
9
- attribute :name_plural , Types::Strict::String
10
- attribute :dsl_file , Types::Strict::String
4
+ # # Domain class holds a list of the entities
5
+ # module KDomain
6
+ # module DomainModel
7
+ #
8
+ # class ErdFile < Dry::Struct
9
+ # attribute :name , Types::Strict::String
10
+ # attribute :name_plural , Types::Strict::String
11
+ # attribute :dsl_file , Types::Strict::String
11
12
 
12
- attribute? :source , Dry::Struct.optional.default(nil) do
13
- attribute :ruby , Types::Strict::String
14
- attribute :public , Types::Strict::String.optional.default(nil)
15
- attribute :private , Types::Strict::String.optional.default(nil)
13
+ # attribute? :source , Dry::Struct.optional.default(nil) do
14
+ # attribute :ruby , Types::Strict::String
15
+ # attribute :public , Types::Strict::String.optional.default(nil)
16
+ # attribute :private , Types::Strict::String.optional.default(nil)
16
17
 
17
- attribute? :all_methods , Dry::Struct.optional.default(nil) do
18
- attribute? :klass , Types::Strict::Array do
19
- attribute :name , Types::Strict::String
20
- attribute :scope , Types::Strict::String # .optional.default(nil)
21
- attribute :class_method , Types::Strict::Bool
22
- attribute :arguments , Types::Strict::String
23
- end
24
- attribute? :instance , Types::Strict::Array do
25
- attribute :name , Types::Strict::String
26
- attribute :scope , Types::Strict::String # .optional.default(nil)
27
- attribute :class_method , Types::Strict::Bool
28
- attribute :arguments , Types::Strict::String
29
- end
30
- attribute? :instance_public , Types::Strict::Array do
31
- attribute :name , Types::Strict::String
32
- attribute :scope , Types::Strict::String # .optional.default(nil)
33
- attribute :class_method , Types::Strict::Bool
34
- attribute :arguments , Types::Strict::String
35
- end
36
- attribute? :instance_private , Types::Strict::Array do
37
- attribute :name , Types::Strict::String
38
- attribute :scope , Types::Strict::String # .optional.default(nil)
39
- attribute :class_method , Types::Strict::Bool
40
- attribute :arguments , Types::Strict::String
41
- end
42
- end
43
- end
44
- attribute? :dsl , Dry::Struct.optional.default(nil) do
45
- attribute :default_scope , Types::Strict::String.optional.default(nil)
18
+ # attribute? :all_methods , Dry::Struct.optional.default(nil) do
19
+ # attribute? :klass , Types::Strict::Array do
20
+ # attribute :name , Types::Strict::String
21
+ # attribute :scope , Types::Strict::String # .optional.default(nil)
22
+ # attribute :class_method , Types::Strict::Bool
23
+ # attribute :arguments , Types::Strict::String
24
+ # end
25
+ # attribute? :instance , Types::Strict::Array do
26
+ # attribute :name , Types::Strict::String
27
+ # attribute :scope , Types::Strict::String # .optional.default(nil)
28
+ # attribute :class_method , Types::Strict::Bool
29
+ # attribute :arguments , Types::Strict::String
30
+ # end
31
+ # attribute? :instance_public , Types::Strict::Array do
32
+ # attribute :name , Types::Strict::String
33
+ # attribute :scope , Types::Strict::String # .optional.default(nil)
34
+ # attribute :class_method , Types::Strict::Bool
35
+ # attribute :arguments , Types::Strict::String
36
+ # end
37
+ # attribute? :instance_private , Types::Strict::Array do
38
+ # attribute :name , Types::Strict::String
39
+ # attribute :scope , Types::Strict::String # .optional.default(nil)
40
+ # attribute :class_method , Types::Strict::Bool
41
+ # attribute :arguments , Types::Strict::String
42
+ # end
43
+ # end
44
+ # end
45
+ # attribute? :dsl , Dry::Struct.optional.default(nil) do
46
+ # attribute :default_scope , Types::Strict::String.optional.default(nil)
46
47
 
47
- attribute? :scopes , Types::Strict::Array do
48
- attribute :name , Types::Strict::String
49
- attribute :scope , Types::Strict::String # .optional.default(nil)
50
- end
51
- attribute? :belongs_to , Types::Strict::Array do
52
- attribute :name , Types::Strict::String
53
- attribute :options , Types::Strict::Hash.optional.default({}.freeze)
54
- attribute :raw_options , Types::Strict::String
55
- end
56
- attribute? :has_one , Types::Strict::Array do
57
- attribute :name , Types::Strict::String
58
- attribute :options , Types::Strict::Hash.optional.default({}.freeze)
59
- attribute :raw_options , Types::Strict::String
60
- end
61
- attribute? :has_many , Types::Strict::Array do
62
- attribute :name , Types::Strict::String
63
- attribute :options , Types::Strict::Hash.optional.default({}.freeze)
64
- attribute :raw_options , Types::Strict::String
65
- end
66
- attribute? :has_and_belongs_to_many , Types::Strict::Array do
67
- attribute :name , Types::Strict::String
68
- attribute :options , Types::Strict::Hash.optional.default({}.freeze)
69
- attribute :raw_options , Types::Strict::String
70
- end
71
- attribute? :validate_on , Types::Strict::Array do
72
- attribute :line , Types::Strict::String
73
- end
74
- attribute? :validates_on , Types::Strict::Array do
75
- attribute :name , Types::Strict::String
76
- attribute :raw_options , Types::Strict::String
77
- end
78
- end
79
- end
80
- # rubocop:enable Metrics/BlockLength
81
- end
82
- end
48
+ # attribute? :scopes , Types::Strict::Array do
49
+ # attribute :name , Types::Strict::String
50
+ # attribute :scope , Types::Strict::String # .optional.default(nil)
51
+ # end
52
+ # attribute? :belongs_to , Types::Strict::Array do
53
+ # attribute :name , Types::Strict::String
54
+ # attribute :options , Types::Strict::Hash.optional.default({}.freeze)
55
+ # attribute :raw_options , Types::Strict::String
56
+ # end
57
+ # attribute? :has_one , Types::Strict::Array do
58
+ # attribute :name , Types::Strict::String
59
+ # attribute :options , Types::Strict::Hash.optional.default({}.freeze)
60
+ # attribute :raw_options , Types::Strict::String
61
+ # end
62
+ # attribute? :has_many , Types::Strict::Array do
63
+ # attribute :name , Types::Strict::String
64
+ # attribute :options , Types::Strict::Hash.optional.default({}.freeze)
65
+ # attribute :raw_options , Types::Strict::String
66
+ # end
67
+ # attribute? :has_and_belongs_to_many , Types::Strict::Array do
68
+ # attribute :name , Types::Strict::String
69
+ # attribute :options , Types::Strict::Hash.optional.default({}.freeze)
70
+ # attribute :raw_options , Types::Strict::String
71
+ # end
72
+ # attribute? :validate_on , Types::Strict::Array do
73
+ # attribute :line , Types::Strict::String
74
+ # end
75
+ # attribute? :validates_on , Types::Strict::Array do
76
+ # attribute :name , Types::Strict::String
77
+ # attribute :raw_options , Types::Strict::String
78
+ # end
79
+ # end
80
+ # end
81
+ # # rubocop:enable Metrics/BlockLength
82
+ # end
83
+ # end