k_domain 0.0.23 → 0.0.28

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 +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