dynamic-active-model 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f4acad4070f218fe60381f8dd22b442ca152fa3528fc309d35f72e6a755f238
4
+ data.tar.gz: 4c15e0e3f7046514a16053d757497be8a16617c96c4e6e5f3b473a4b0a642dc2
5
+ SHA512:
6
+ metadata.gz: edf688fbec02059b722d397f47fb4a2872972db6e5855e4a62641d91f57d4f07fc0d58240ca938f9e38c0277a84498e2d7b4ae2857de5c9ee81856b253ca9b00
7
+ data.tar.gz: 766b08e10f4a11c25329a21d646f887a296c9b04553db92c7a3bffcb703c837034cfea3b53ae0780d472b00471aa6400e37d1b19c1514ee1f850eaf14a382801
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # DynamicActiveModel module for create ActiveRecord models
4
+ module DynamicActiveModel
5
+ autoload :Database, 'dynamic-active-model/database'
6
+ autoload :Factory, 'dynamic-active-model/factory'
7
+ autoload :ForeignKey, 'dynamic-active-model/foreign_key'
8
+ autoload :Relations, 'dynamic-active-model/relations'
9
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicActiveModel
4
+ # DynamicActiveModel::Database iterates over the tables of a
5
+ # database and create ActiveRecord models
6
+ class Database
7
+ attr_reader :table_class_names,
8
+ :factory,
9
+ :models
10
+
11
+ def initialize(base_module, connection_options, base_class_name = nil)
12
+ @factory = Factory.new(base_module, connection_options, base_class_name)
13
+ @table_class_names = {}
14
+ @skip_tables = []
15
+ @skip_table_matchers = []
16
+ @models = []
17
+ end
18
+
19
+ def skip_table(table)
20
+ if table.is_a?(Regexp)
21
+ @skip_table_matchers << table
22
+ else
23
+ @skip_tables << table.to_s
24
+ end
25
+ end
26
+
27
+ def table_class_name(table_name, class_name)
28
+ @table_class_names[table_name.to_s] = class_name
29
+ end
30
+
31
+ def create_models!
32
+ @factory.base_class.connection.tables.each do |table_name|
33
+ next if skip_table?(table_name)
34
+
35
+ @models << @factory.create(table_name, @table_class_names[table_name])
36
+ end
37
+ end
38
+
39
+ def skip_tables
40
+ @skip_tables + @skip_table_matchers
41
+ end
42
+
43
+ private
44
+
45
+ def skip_table?(table_name)
46
+ @skip_tables.include?(table_name) ||
47
+ @skip_table_matchers.any? { |r| r.match(table_name) }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicActiveModel
4
+ # DynamicActiveModel::Factory creates ActiveRecord class for tables
5
+ class Factory
6
+ attr_writer :base_class
7
+
8
+ def initialize(base_module, connection_options, base_class_name = nil)
9
+ @base_module = base_module
10
+ @connection_options = connection_options
11
+ @base_class_name = base_class_name || :DynamicAbstractBase
12
+ end
13
+
14
+ def create(table_name, class_name = nil)
15
+ class_name ||= generate_class_name(table_name)
16
+ kls = Class.new(base_class) do
17
+ self.table_name = table_name
18
+ end
19
+ @base_module.const_set(class_name, kls)
20
+ @base_module.const_get(class_name)
21
+ end
22
+
23
+ # rubocop:disable MethodLength
24
+ def base_class
25
+ @base_class ||=
26
+ begin
27
+ require 'active_record'
28
+
29
+ kls = Class.new(ActiveRecord::Base) do
30
+ self.abstract_class = true
31
+ end
32
+ @base_module.const_set(@base_class_name, kls)
33
+
34
+ kls = @base_module.const_get(@base_class_name)
35
+ kls.establish_connection @connection_options
36
+ kls
37
+ end
38
+ end
39
+ # rubocop:enable MethodLength
40
+
41
+ def generate_class_name(table_name)
42
+ table_name.classify
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicActiveModel
4
+ # DynamicActiveModel::ForeignKey tracks foreign keys related to the model
5
+ class ForeignKey
6
+ attr_reader :model,
7
+ :keys
8
+
9
+ DEFAULT_ID_SUFFIX = '_id'
10
+
11
+ def self.id_suffix
12
+ @id_suffix || DEFAULT_ID_SUFFIX
13
+ end
14
+
15
+ # rubocop:disable Style/TrivialAccessors
16
+ def self.id_suffix=(val)
17
+ @id_suffix = val
18
+ end
19
+ # rubocop:enable Style/TrivialAccessors
20
+
21
+ def initialize(model)
22
+ @model = model
23
+ @keys = {}
24
+ add(generate_foreign_key(model.table_name), model.table_name.underscore)
25
+ end
26
+
27
+ def add(key, relationship_name)
28
+ @keys[key] = relationship_name
29
+ end
30
+
31
+ def generate_foreign_key(table_name)
32
+ table_name.singularize + self.class.id_suffix
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DynamicActiveModel
4
+ # DynamicActiveModel::Relations iterates over the models of a
5
+ # database and adds has_many and belongs_to based on foreign keys
6
+ class Relations
7
+ attr_reader :database
8
+
9
+ def initialize(database)
10
+ @database = database
11
+ @foreign_keys = database.models.each_with_object({}) do |model, hsh|
12
+ hsh[model.table_name] = ForeignKey.new(model)
13
+ end
14
+ end
15
+
16
+ def add_foreign_key(table_name, foreign_key, relationship_name)
17
+ @foreign_keys[table_name].add(foreign_key, relationship_name)
18
+ end
19
+
20
+ # iterates over the models and adds relationships
21
+ def build!
22
+ foreign_key_to_models = create_foreign_key_to_model_map
23
+
24
+ @database.models.each do |model|
25
+ model.column_names.each do |column_name|
26
+ next unless foreign_key_to_models[column_name]
27
+
28
+ foreign_key_to_models[column_name].each do |foreign_model, relationship_name|
29
+ next if foreign_model == model
30
+
31
+ add_relationships(relationship_name, model, foreign_model, column_name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def add_relationships(relationship_name, model, belongs_to_model, foreign_key)
40
+ add_belongs_to(relationship_name, model, belongs_to_model, foreign_key)
41
+ add_has_many(belongs_to_model, model, foreign_key)
42
+ end
43
+
44
+ def add_belongs_to(relationship_name, model, belongs_to_model, foreign_key)
45
+ model.belongs_to(
46
+ relationship_name.singularize.to_sym,
47
+ class_name: belongs_to_model.name,
48
+ foreign_key: foreign_key,
49
+ primary_key: belongs_to_model.primary_key
50
+ )
51
+ end
52
+
53
+ def add_has_many(model, has_many_model, foreign_key)
54
+ model.has_many(
55
+ has_many_model.table_name.underscore.pluralize.to_sym,
56
+ class_name: has_many_model.name,
57
+ foreign_key: foreign_key,
58
+ primary_key: has_many_model.primary_key
59
+ )
60
+ end
61
+
62
+ def create_foreign_key_to_model_map
63
+ @foreign_keys.values.each_with_object({}) do |foreign_key, hsh|
64
+ foreign_key.keys.each do |key, relationship_name|
65
+ hsh[key] ||= []
66
+ hsh[key] << [foreign_key.model, relationship_name]
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dynamic-active-model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Doug Youch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-07-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Dynamically create ActiveRecord models for tables
28
+ email: dougyouch@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/dynamic-active-model.rb
34
+ - lib/dynamic-active-model/database.rb
35
+ - lib/dynamic-active-model/factory.rb
36
+ - lib/dynamic-active-model/foreign_key.rb
37
+ - lib/dynamic-active-model/relations.rb
38
+ homepage: https://github.com/dougyouch/dynamic-active-model
39
+ licenses: []
40
+ metadata: {}
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubygems_version: 3.0.3
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: Dynamic ActiveRecord Models
60
+ test_files: []