dynamic-active-model 0.1.0 → 0.2.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 67d4e71c097cafd08ed7e9c3ed2ffd4d8b22b5787fd2f6ab498a709b75de5215
|
4
|
+
data.tar.gz: a5cad0b2293d861f93bdf9d6c8fbc983ca9c4af1ab9bb60c22216c074e2b01c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5939469d103fb9c6a6d71ea987e6b0f8fe9c117d1014ca5d752c25307c1d5ff586d64cebae3571cc1eb276e9cfd760e577bae2066c9812223055c1f309b0cb50
|
7
|
+
data.tar.gz: 422a33565554689d2055122cc45234e7fd4c7f1f766f018b4fd080df6c86051cc79d950fec706702f489bd225793e84b3dc1d4cc7b66ae2dd2667fe507e0f5f1
|
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'dynamic-active-model'
|
5
|
+
require 'optparse'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
DEFAULT_CONFIG_FILE = "#{ENV['HOME']}/.dynamic-db-explorer.yml"
|
9
|
+
|
10
|
+
options = {
|
11
|
+
base_module: Object,
|
12
|
+
connection_options: {},
|
13
|
+
skip_tables: [],
|
14
|
+
relationships: {},
|
15
|
+
config_file: nil,
|
16
|
+
config_section: nil,
|
17
|
+
class_files_dir: nil
|
18
|
+
}
|
19
|
+
|
20
|
+
# rubocop:disable Metrics/BlockLength
|
21
|
+
OptionParser.new do |opts|
|
22
|
+
opts.banner = 'Usage: dynamic-db-explorer'
|
23
|
+
|
24
|
+
opts.on('-h', '--help', 'Prints this help') do
|
25
|
+
puts opts
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('--username USERMNAME', 'DB username') do |v|
|
30
|
+
options[:connection_options][:username] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
opts.on('--host HOST', 'DB host') do |v|
|
34
|
+
options[:connection_options][:host] = v
|
35
|
+
end
|
36
|
+
|
37
|
+
opts.on('--port PORT', 'DB port') do |v|
|
38
|
+
options[:connection_options][:port] = v
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on('--password PASSWORD', 'DB password') do |v|
|
42
|
+
options[:connection_options][:password] = v
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on('--adapter ADAPTER', 'DB adapter') do |v|
|
46
|
+
options[:connection_options][:adapter] = v
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('--database DATABASE', 'DB name') do |v|
|
50
|
+
options[:connection_options][:database] = v
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on('--module MODULE_NAME', 'module name') do |v|
|
54
|
+
Object.const_set(v, Module.new)
|
55
|
+
options[:base_module] = Object.const_get(v)
|
56
|
+
end
|
57
|
+
|
58
|
+
opts.on('-c', '--config FILE', "config file, default #{DEFAULT_CONFIG_FILE}") do |v|
|
59
|
+
options[:config_file] = v
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on('-s', '--section SECTION', 'config file section') do |v|
|
63
|
+
options[:config_file] = DEFAULT_CONFIG_FILE if !options[:config_file] && File.exist?(DEFAULT_CONFIG_FILE)
|
64
|
+
options[:config_section] = v
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on('--create-class-files DIR', 'Create ActiveRecord class files') do |v|
|
68
|
+
raise("#{v} not found") unless File.exist?(v)
|
69
|
+
|
70
|
+
options[:class_files_dir] = v
|
71
|
+
end
|
72
|
+
end.parse!
|
73
|
+
# rubocop:enable Metrics/BlockLength
|
74
|
+
|
75
|
+
if options[:config_file]
|
76
|
+
raise('must specify a section') unless options[:config_section]
|
77
|
+
|
78
|
+
config = YAML.load_file(options[:config_file])[options[:config_section]]
|
79
|
+
options[:skip_tables] = config.delete('skip_tables') || []
|
80
|
+
options[:relationships] = config.delete('relationships') || {}
|
81
|
+
if (module_name = config.delete('module'))
|
82
|
+
Object.const_set(module_name, Module.new)
|
83
|
+
options[:base_module] = Object.const_get(module_name)
|
84
|
+
end
|
85
|
+
options[:connection_options] = config.each_with_object({}) { |(name, value), hsh| hsh[name.to_sym] = value }
|
86
|
+
end
|
87
|
+
|
88
|
+
database = DynamicActiveModel::Explorer.explore(
|
89
|
+
options[:base_module],
|
90
|
+
options[:connection_options],
|
91
|
+
options[:skip_tables],
|
92
|
+
options[:relationships]
|
93
|
+
)
|
94
|
+
|
95
|
+
if options[:class_files_dir]
|
96
|
+
database.models.each do |model|
|
97
|
+
DynamicActiveModel::TemplateClassFile.new(model).create_template!(options[:class_files_dir])
|
98
|
+
end
|
99
|
+
else
|
100
|
+
require 'irb'
|
101
|
+
IRB.start(__FILE__)
|
102
|
+
end
|
data/lib/dynamic-active-model.rb
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
# DynamicActiveModel module for create ActiveRecord models
|
4
4
|
module DynamicActiveModel
|
5
5
|
autoload :Database, 'dynamic-active-model/database'
|
6
|
+
autoload :Explorer, 'dynamic-active-model/explorer'
|
6
7
|
autoload :Factory, 'dynamic-active-model/factory'
|
7
8
|
autoload :ForeignKey, 'dynamic-active-model/foreign_key'
|
8
9
|
autoload :Relations, 'dynamic-active-model/relations'
|
10
|
+
autoload :TemplateClassFile, 'dynamic-active-model/template_class_file'
|
9
11
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicActiveModel
|
4
|
+
# DynamicActiveModel::EWplorer creates models and relationships
|
5
|
+
module Explorer
|
6
|
+
def self.explore(base_module, connection_options, skip_tables = [], relationships = {})
|
7
|
+
database = create_models!(base_module, connection_options, skip_tables)
|
8
|
+
build_relationships!(database, relationships)
|
9
|
+
database
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.create_models!(base_module, connection_options, skip_tables)
|
13
|
+
database = Database.new(base_module, connection_options)
|
14
|
+
skip_tables.each do |table_name|
|
15
|
+
table_name = Regexp.new("^#{table_name}") if table_name.include?('*')
|
16
|
+
database.skip_table(table_name)
|
17
|
+
end
|
18
|
+
database.create_models!
|
19
|
+
database
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.build_relationships!(database, relationships)
|
23
|
+
relations = Relations.new(database)
|
24
|
+
relationships.each do |table_name, foreign_keys|
|
25
|
+
foreign_keys.each do |foreign_key, relationship_name|
|
26
|
+
relations.add_foreign_key(table_name, foreign_key, relationship_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
relations.build!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DynamicActiveModel
|
4
|
+
# DynamicActiveModel::TemplateClassFile creates ActiveRecord file for model
|
5
|
+
class TemplateClassFile
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_template!(dir)
|
11
|
+
file = dir + '/' + @model.name.underscore + '.rb'
|
12
|
+
File.open(file, 'wb') { |f| f.write(to_s) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
str = "class #{@model.name} < ActiveRecord::Base\n".dup
|
17
|
+
str << " self.table_name = #{@model.table_name.to_sym.inspect}\n" unless @model.name.underscore.pluralize == @model.table_name
|
18
|
+
all_has_many_relationships.each do |assoc|
|
19
|
+
append_association!(str, assoc)
|
20
|
+
end
|
21
|
+
all_belongs_to_relationships.each do |assoc|
|
22
|
+
append_association!(str, assoc)
|
23
|
+
end
|
24
|
+
str << "end\n"
|
25
|
+
str
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def all_has_many_relationships
|
31
|
+
@model.reflect_on_all_associations.select do |assoc|
|
32
|
+
assoc.is_a?(ActiveRecord::Reflection::HasManyReflection)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def all_belongs_to_relationships
|
37
|
+
@model.reflect_on_all_associations.select do |assoc|
|
38
|
+
assoc.is_a?(ActiveRecord::Reflection::BelongsToReflection)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def append_association!(str, assoc)
|
43
|
+
assoc_type = assoc.is_a?(ActiveRecord::Reflection::HasManyReflection) ? 'has_many' : 'belongs_to'
|
44
|
+
association_options = assoc_type == 'has_many' ? has_many_association_options(assoc) : belongs_to_association_options(assoc)
|
45
|
+
str << " #{assoc_type} #{assoc.name.inspect}"
|
46
|
+
unless association_options.empty?
|
47
|
+
association_options.each do |name, value|
|
48
|
+
str << ", #{name}: '#{value}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
str << "\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_many_association_options(assoc)
|
55
|
+
options = {}
|
56
|
+
options[:class_name] = assoc.options[:class_name] unless assoc.options[:class_name].underscore.pluralize == assoc.name.to_s
|
57
|
+
options[:foreign_key] = assoc.options[:foreign_key] unless assoc.options[:foreign_key] == default_foreign_key_name
|
58
|
+
options[:primary_key] = assoc.options[:primary_key] unless assoc.options[:primary_key] == 'id'
|
59
|
+
options
|
60
|
+
end
|
61
|
+
|
62
|
+
def belongs_to_association_options(assoc)
|
63
|
+
options = {}
|
64
|
+
options[:class_name] = assoc.options[:class_name] unless assoc.options[:class_name] == assoc.name.to_s.classify
|
65
|
+
options[:foreign_key] = assoc.options[:foreign_key] unless assoc.options[:foreign_key] == (assoc.options[:class_name].underscore + '_id')
|
66
|
+
options[:primary_key] = assoc.options[:primary_key] unless assoc.options[:primary_key] == 'id'
|
67
|
+
options
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_foreign_key_name
|
71
|
+
@model.table_name.underscore.singularize + '_id'
|
72
|
+
end
|
73
|
+
|
74
|
+
def const_get(class_name)
|
75
|
+
class_name.split('::').inject(Object) { |mod, name| mod.const_get(name) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamic-active-model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Doug Youch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -26,15 +26,19 @@ dependencies:
|
|
26
26
|
version: '0'
|
27
27
|
description: Dynamically create ActiveRecord models for tables
|
28
28
|
email: dougyouch@gmail.com
|
29
|
-
executables:
|
29
|
+
executables:
|
30
|
+
- dynamic-db-explorer
|
30
31
|
extensions: []
|
31
32
|
extra_rdoc_files: []
|
32
33
|
files:
|
34
|
+
- bin/dynamic-db-explorer
|
33
35
|
- lib/dynamic-active-model.rb
|
34
36
|
- lib/dynamic-active-model/database.rb
|
37
|
+
- lib/dynamic-active-model/explorer.rb
|
35
38
|
- lib/dynamic-active-model/factory.rb
|
36
39
|
- lib/dynamic-active-model/foreign_key.rb
|
37
40
|
- lib/dynamic-active-model/relations.rb
|
41
|
+
- lib/dynamic-active-model/template_class_file.rb
|
38
42
|
homepage: https://github.com/dougyouch/dynamic-active-model
|
39
43
|
licenses: []
|
40
44
|
metadata: {}
|