dynamic-active-model 0.1.0
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.
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: []
|