jw-rails-erd 1.4.5
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 +7 -0
- data/README.md +86 -0
- data/Rakefile +20 -0
- data/bin/erd +4 -0
- data/lib/generators/erd/USAGE +4 -0
- data/lib/generators/erd/install_generator.rb +14 -0
- data/lib/generators/erd/templates/auto_generate_diagram.rake +6 -0
- data/lib/rails-erd.rb +1 -0
- data/lib/rails_erd/cli.rb +164 -0
- data/lib/rails_erd/config.rb +97 -0
- data/lib/rails_erd/custom.rb +99 -0
- data/lib/rails_erd/diagram/graphviz.rb +295 -0
- data/lib/rails_erd/diagram/templates/node.html.erb +14 -0
- data/lib/rails_erd/diagram/templates/node.record.erb +4 -0
- data/lib/rails_erd/diagram.rb +188 -0
- data/lib/rails_erd/domain/attribute.rb +160 -0
- data/lib/rails_erd/domain/entity.rb +104 -0
- data/lib/rails_erd/domain/relationship/cardinality.rb +118 -0
- data/lib/rails_erd/domain/relationship.rb +203 -0
- data/lib/rails_erd/domain/specialization.rb +90 -0
- data/lib/rails_erd/domain.rb +153 -0
- data/lib/rails_erd/railtie.rb +10 -0
- data/lib/rails_erd/tasks.rake +58 -0
- data/lib/rails_erd/version.rb +4 -0
- data/lib/rails_erd.rb +73 -0
- data/lib/tasks/auto_generate_diagram.rake +21 -0
- data/test/support_files/erdconfig.another_example +3 -0
- data/test/support_files/erdconfig.example +19 -0
- data/test/support_files/erdconfig.exclude.example +19 -0
- data/test/test_helper.rb +160 -0
- data/test/unit/attribute_test.rb +316 -0
- data/test/unit/cardinality_test.rb +123 -0
- data/test/unit/config_test.rb +110 -0
- data/test/unit/diagram_test.rb +352 -0
- data/test/unit/domain_test.rb +258 -0
- data/test/unit/entity_test.rb +252 -0
- data/test/unit/graphviz_test.rb +461 -0
- data/test/unit/rake_task_test.rb +174 -0
- data/test/unit/relationship_test.rb +476 -0
- data/test/unit/specialization_test.rb +67 -0
- metadata +155 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
def say(message)
|
2
|
+
puts message unless Rake.application.options.silent
|
3
|
+
end
|
4
|
+
|
5
|
+
namespace :erd do
|
6
|
+
task :options do
|
7
|
+
(RailsERD.options.keys.map(&:to_s) & ENV.keys).each do |option|
|
8
|
+
RailsERD.options[option.to_sym] = case ENV[option]
|
9
|
+
when "true", "yes" then true
|
10
|
+
when "false", "no" then false
|
11
|
+
when /,/ then ENV[option].split(/\s*,\s*/)
|
12
|
+
else ENV[option].to_sym
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :load_models do
|
18
|
+
say "Loading application environment..."
|
19
|
+
Rake::Task[:environment].invoke
|
20
|
+
|
21
|
+
say "Loading code in search of Active Record models..."
|
22
|
+
begin
|
23
|
+
Rails.application.eager_load!
|
24
|
+
rescue Exception => err
|
25
|
+
if Rake.application.options.trace
|
26
|
+
raise
|
27
|
+
else
|
28
|
+
trace = Rails.backtrace_cleaner.clean(err.backtrace)
|
29
|
+
error = (["Loading models failed!\nError occurred while loading application: #{err} (#{err.class})"] + trace).join("\n ")
|
30
|
+
raise error
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
raise "Active Record was not loaded." unless defined? ActiveRecord
|
35
|
+
end
|
36
|
+
|
37
|
+
task :generate => [:options, :load_models] do
|
38
|
+
say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
|
39
|
+
|
40
|
+
require "rails_erd/diagram/graphviz"
|
41
|
+
file = RailsERD::Diagram::Graphviz.create
|
42
|
+
|
43
|
+
say "Done! Saved diagram to #{file}."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Generate an Entity-Relationship Diagram based on your models"
|
48
|
+
task :erd => "erd:generate", :arg1, :arg2, :arg3 do |t, args|
|
49
|
+
say "Usage: rake erd <classname> <outputfile> <traversal depth>"
|
50
|
+
if args[0] == nil
|
51
|
+
say "Required field: Root Class node to start with"
|
52
|
+
end
|
53
|
+
if args[1] == nil
|
54
|
+
say "Required field: output file name"
|
55
|
+
end
|
56
|
+
args[2] ||= 1
|
57
|
+
RailsERD::Custom.new(args[0], args[1], args[2])
|
58
|
+
end
|
data/lib/rails_erd.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "active_support/ordered_options"
|
2
|
+
require "rails_erd/railtie" if defined? Rails
|
3
|
+
require "rails_erd/config"
|
4
|
+
|
5
|
+
# Welcome to the API documentation of Rails ERD. If you wish to extend or
|
6
|
+
# customise the output that is generated by Rails ERD, you have come to the
|
7
|
+
# right place.
|
8
|
+
#
|
9
|
+
# == Creating custom output
|
10
|
+
#
|
11
|
+
# If you want to create your own kind of diagrams, or some other output, a
|
12
|
+
# good starting point is the RailsERD::Diagram class. It can serve as the base
|
13
|
+
# of your output generation code.
|
14
|
+
#
|
15
|
+
# == Options
|
16
|
+
#
|
17
|
+
# Rails ERD provides several options that allow you to customise the
|
18
|
+
# generation of the diagram and the domain model itself. For an overview of
|
19
|
+
# all options available in Rails ERD, see README.rdoc.
|
20
|
+
#
|
21
|
+
# You can specify the option on the command line if you use Rails ERD with
|
22
|
+
# Rake:
|
23
|
+
#
|
24
|
+
# % rake erd orientation=vertical title='My model diagram'
|
25
|
+
#
|
26
|
+
# When using Rails ERD from within Ruby, you can set the options on the
|
27
|
+
# RailsERD namespace module:
|
28
|
+
#
|
29
|
+
# RailsERD.options.orientation = :vertical
|
30
|
+
# RailsERD.options.title = "My model diagram"
|
31
|
+
module RailsERD
|
32
|
+
class << self
|
33
|
+
# Access to default options. Any instance of RailsERD::Domain and
|
34
|
+
# RailsERD::Diagram will use these options unless overridden.
|
35
|
+
attr_accessor :options
|
36
|
+
|
37
|
+
def default_options
|
38
|
+
ActiveSupport::OrderedOptions[
|
39
|
+
:attributes, :content,
|
40
|
+
:disconnected, true,
|
41
|
+
:filename, "erd",
|
42
|
+
:filetype, :pdf,
|
43
|
+
:indirect, true,
|
44
|
+
:inheritance, false,
|
45
|
+
:markup, true,
|
46
|
+
:notation, :simple,
|
47
|
+
:orientation, :horizontal,
|
48
|
+
:polymorphism, false,
|
49
|
+
:sort, true,
|
50
|
+
:warn, true,
|
51
|
+
:title, true,
|
52
|
+
:exclude, nil,
|
53
|
+
:only, nil,
|
54
|
+
:prepend_primary, false
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module Inspectable # @private :nodoc:
|
60
|
+
def inspection_attributes(*attributes)
|
61
|
+
attribute_inspection = attributes.collect { |attribute|
|
62
|
+
" @#{attribute}=\#{[Symbol, String].include?(#{attribute}.class) ? #{attribute}.inspect : #{attribute}}"
|
63
|
+
}.join
|
64
|
+
class_eval <<-RUBY
|
65
|
+
def inspect
|
66
|
+
"#<\#{self.class}:0x%.14x#{attribute_inspection}>" % (object_id << 1)
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
self.options = default_options.merge(Config.load)
|
73
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :db do
|
2
|
+
task :migrate do
|
3
|
+
ERDGraph::Migration.update_model
|
4
|
+
end
|
5
|
+
|
6
|
+
namespace :migrate do
|
7
|
+
[:change, :up, :down, :reset, :redo].each do |t|
|
8
|
+
task t do
|
9
|
+
ERDGraph::Migration.update_model
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ERDGraph
|
16
|
+
class Migration
|
17
|
+
def self.update_model
|
18
|
+
Rake::Task['erd'].invoke
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
attributes:
|
2
|
+
- content
|
3
|
+
- foreign_key
|
4
|
+
- inheritance
|
5
|
+
- false
|
6
|
+
disconnected: true
|
7
|
+
filename: erd
|
8
|
+
filetype: pdf
|
9
|
+
indirect: true
|
10
|
+
inheritance: false
|
11
|
+
markup: true
|
12
|
+
notation: simple
|
13
|
+
orientation: horizontal
|
14
|
+
polymorphism: false
|
15
|
+
warn: true
|
16
|
+
title: sample title
|
17
|
+
exclude:
|
18
|
+
only:
|
19
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
attributes:
|
2
|
+
- content
|
3
|
+
- foreign_key
|
4
|
+
- inheritance
|
5
|
+
- false
|
6
|
+
disconnected: true
|
7
|
+
filename: erd
|
8
|
+
filetype: pdf
|
9
|
+
indirect: true
|
10
|
+
inheritance: false
|
11
|
+
markup: true
|
12
|
+
notation: simple
|
13
|
+
orientation: horizontal
|
14
|
+
polymorphism: false
|
15
|
+
warn: true
|
16
|
+
title: sample title
|
17
|
+
exclude: Book,Author
|
18
|
+
only:
|
19
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require "active_record"
|
5
|
+
|
6
|
+
if ActiveSupport::VERSION::MAJOR >= 4
|
7
|
+
require "minitest/autorun"
|
8
|
+
require 'mocha/mini_test'
|
9
|
+
else
|
10
|
+
require "test/unit"
|
11
|
+
require 'mocha/test_unit'
|
12
|
+
end
|
13
|
+
|
14
|
+
require "rails_erd/domain"
|
15
|
+
|
16
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
|
17
|
+
|
18
|
+
if ActiveSupport::TestCase.respond_to?(:test_order=)
|
19
|
+
ActiveSupport::TestCase.test_order = :random
|
20
|
+
end
|
21
|
+
|
22
|
+
class ActiveSupport::TestCase
|
23
|
+
include RailsERD
|
24
|
+
|
25
|
+
setup :reset_config_file
|
26
|
+
teardown :reset_domain
|
27
|
+
|
28
|
+
def create_table(table, columns = {}, pk = nil)
|
29
|
+
opts = if pk then { :primary_key => pk } else { :id => false } end
|
30
|
+
ActiveRecord::Schema.instance_eval do
|
31
|
+
suppress_messages do
|
32
|
+
create_table table, opts do |t|
|
33
|
+
columns.each do |column, type|
|
34
|
+
t.send type, column
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
ActiveRecord::Base.clear_cache!
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_column(*args)
|
43
|
+
ActiveRecord::Schema.instance_eval do
|
44
|
+
suppress_messages do
|
45
|
+
add_column(*args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
ActiveRecord::Base.clear_cache!
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_model(name, *args, &block)
|
52
|
+
superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
|
53
|
+
columns = args.first || {}
|
54
|
+
klass = Object.const_set name.to_sym, Class.new(superklass)
|
55
|
+
if superklass == ActiveRecord::Base || superklass.abstract_class?
|
56
|
+
create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key rescue nil
|
57
|
+
end
|
58
|
+
klass.class_eval(&block) if block_given?
|
59
|
+
Object.const_get(name.to_sym)
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_models(*names)
|
63
|
+
names.each do |name|
|
64
|
+
create_model name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def collect_stdout
|
69
|
+
stdout = $stdout
|
70
|
+
$stdout = StringIO.new
|
71
|
+
yield
|
72
|
+
$stdout.rewind
|
73
|
+
$stdout.read
|
74
|
+
ensure
|
75
|
+
$stdout = stdout
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_simple_domain
|
79
|
+
create_model "Beer", :bar => :references do
|
80
|
+
belongs_to :bar
|
81
|
+
end
|
82
|
+
create_model "Bar"
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_one_to_one_assoc_domain
|
86
|
+
create_model "One" do
|
87
|
+
has_one :other
|
88
|
+
end
|
89
|
+
create_model "Other", :one => :references do
|
90
|
+
belongs_to :one
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_one_to_many_assoc_domain
|
95
|
+
create_model "One" do
|
96
|
+
has_many :many
|
97
|
+
end
|
98
|
+
create_model "Many", :one => :references do
|
99
|
+
belongs_to :one
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_many_to_many_assoc_domain
|
104
|
+
create_model "Many" do
|
105
|
+
has_and_belongs_to_many :more
|
106
|
+
end
|
107
|
+
create_model "More" do
|
108
|
+
has_and_belongs_to_many :many
|
109
|
+
end
|
110
|
+
create_table "manies_mores", :many_id => :integer, :more_id => :integer
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_specialization
|
114
|
+
create_model "Beverage", :type => :string
|
115
|
+
create_model "Beer", Beverage
|
116
|
+
end
|
117
|
+
|
118
|
+
def create_polymorphic_generalization
|
119
|
+
create_model "Cannon"
|
120
|
+
create_model "Galleon" do
|
121
|
+
has_many :cannons, :as => :defensible
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def create_abstract_generalization
|
126
|
+
create_model "Structure" do
|
127
|
+
self.abstract_class = true
|
128
|
+
end
|
129
|
+
create_model "Palace", Structure
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def reset_config_file
|
135
|
+
RailsERD::Config.send :remove_const, :USER_WIDE_CONFIG_FILE
|
136
|
+
RailsERD::Config.send :const_set, :USER_WIDE_CONFIG_FILE,
|
137
|
+
File.expand_path("../../examples/erdconfig.not_exists", __FILE__)
|
138
|
+
|
139
|
+
RailsERD::Config.send :remove_const, :CURRENT_CONFIG_FILE
|
140
|
+
RailsERD::Config.send :const_set, :CURRENT_CONFIG_FILE,
|
141
|
+
File.expand_path("../../examples/erdconfig.not_exists", __FILE__)
|
142
|
+
|
143
|
+
RailsERD.options = RailsERD.default_options.merge(Config.load)
|
144
|
+
end
|
145
|
+
|
146
|
+
def reset_domain
|
147
|
+
if defined? ActiveRecord
|
148
|
+
ActiveRecord::Base.descendants.each do |model|
|
149
|
+
model.reset_column_information
|
150
|
+
Object.send :remove_const, model.name.to_sym if Object.const_defined? model.name.to_sym
|
151
|
+
end
|
152
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
153
|
+
ActiveRecord::Base.connection.drop_table table
|
154
|
+
end
|
155
|
+
ActiveRecord::Base.direct_descendants.clear
|
156
|
+
ActiveSupport::Dependencies::Reference.clear!
|
157
|
+
ActiveRecord::Base.clear_cache!
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
class AttributeTest < ActiveSupport::TestCase
|
5
|
+
def with_native_limit(type, new_limit)
|
6
|
+
ActiveRecord::Base.connection.class_eval do
|
7
|
+
define_method :native_database_types do
|
8
|
+
super().tap do |types|
|
9
|
+
types[type][:limit] = new_limit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
ActiveRecord::Base.connection.class_eval do
|
16
|
+
define_method :native_database_types do
|
17
|
+
super()
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_attribute(model, name)
|
23
|
+
Domain::Attribute.new(Domain.generate, model, model.columns_hash[name])
|
24
|
+
end
|
25
|
+
|
26
|
+
# Attribute ================================================================
|
27
|
+
test "column should return database column" do
|
28
|
+
create_model "Foo", :my_column => :string
|
29
|
+
assert_equal Foo.columns_hash["my_column"],
|
30
|
+
Domain::Attribute.from_model(Domain.new, Foo).reject(&:primary_key?).first.column
|
31
|
+
end
|
32
|
+
|
33
|
+
test "from_model should return attributes with sorted order if sort is true" do
|
34
|
+
RailsERD.options[:sort] = true
|
35
|
+
create_model "Foo"
|
36
|
+
add_column :foos, :a, :string
|
37
|
+
assert_equal %w{a id}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
|
38
|
+
end
|
39
|
+
|
40
|
+
test "from_model should return attributes with original order if sort is false" do
|
41
|
+
RailsERD.options[:sort] = false
|
42
|
+
create_model "Foo"
|
43
|
+
add_column :foos, :a, :string
|
44
|
+
assert_equal %w{id a}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
|
45
|
+
end
|
46
|
+
|
47
|
+
test "from_model should return attributes with PK first if prepend_primary is true" do
|
48
|
+
RailsERD.options[:sort] = true
|
49
|
+
RailsERD.options[:prepend_primary] = true
|
50
|
+
|
51
|
+
create_model "Foo"
|
52
|
+
add_column :foos, :a, :string
|
53
|
+
|
54
|
+
assert_equal %w{id a}, Domain::Attribute.from_model(Domain.new, Foo).map(&:name)
|
55
|
+
end
|
56
|
+
|
57
|
+
test "spaceship should sort attributes by name" do
|
58
|
+
create_model "Foo", :a => :string, :b => :string, :c => :string
|
59
|
+
a = create_attribute(Foo, "a")
|
60
|
+
b = create_attribute(Foo, "b")
|
61
|
+
c = create_attribute(Foo, "c")
|
62
|
+
assert_equal [a, b, c], [c, a, b].sort
|
63
|
+
end
|
64
|
+
|
65
|
+
test "inspect should show column" do
|
66
|
+
create_model "Foo", :my_column => :string
|
67
|
+
assert_match %r{#<RailsERD::Domain::Attribute:.* @name="my_column" @type=:string>},
|
68
|
+
Domain::Attribute.new(Domain.new, Foo, Foo.columns_hash["my_column"]).inspect
|
69
|
+
end
|
70
|
+
|
71
|
+
test "type should return attribute type" do
|
72
|
+
create_model "Foo", :a => :binary
|
73
|
+
assert_equal :binary, create_attribute(Foo, "a").type
|
74
|
+
end
|
75
|
+
|
76
|
+
test "type should return native type if unsupported by rails" do
|
77
|
+
create_model "Foo"
|
78
|
+
ActiveRecord::Schema.define do
|
79
|
+
suppress_messages do
|
80
|
+
add_column "foos", "a", "REAL"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
assert_equal :real, create_attribute(Foo, "a").type
|
84
|
+
end
|
85
|
+
|
86
|
+
# Attribute properties =====================================================
|
87
|
+
test "mandatory should return false by default" do
|
88
|
+
create_model "Foo", :column => :string
|
89
|
+
assert_equal false, create_attribute(Foo, "column").mandatory?
|
90
|
+
end
|
91
|
+
|
92
|
+
test "mandatory should return true if attribute has a presence validator" do
|
93
|
+
create_model "Foo", :column => :string do
|
94
|
+
validates :column, :presence => true
|
95
|
+
end
|
96
|
+
assert_equal true, create_attribute(Foo, "column").mandatory?
|
97
|
+
end
|
98
|
+
|
99
|
+
test "mandatory should return true if attribute has a not null constraint" do
|
100
|
+
create_model "Foo"
|
101
|
+
add_column :foos, :column, :string, :null => false, :default => ""
|
102
|
+
assert_equal true, create_attribute(Foo, "column").mandatory?
|
103
|
+
end
|
104
|
+
|
105
|
+
test "primary_key should return false by default" do
|
106
|
+
create_model "Bar", :my_key => :integer
|
107
|
+
assert_equal false, create_attribute(Bar, "my_key").primary_key?
|
108
|
+
end
|
109
|
+
|
110
|
+
test "primary_key should return true if column is used as primary key" do
|
111
|
+
create_model "Bar", :my_key => :integer do
|
112
|
+
self.primary_key = :my_key
|
113
|
+
end
|
114
|
+
assert_equal true, create_attribute(Bar, "my_key").primary_key?
|
115
|
+
end
|
116
|
+
|
117
|
+
test "foreign_key should return false by default" do
|
118
|
+
create_model "Foo", :bar => :references
|
119
|
+
assert_equal false, create_attribute(Foo, "bar_id").foreign_key?
|
120
|
+
end
|
121
|
+
|
122
|
+
test "foreign_key should return true if it is used in an association" do
|
123
|
+
create_model "Foo", :bar => :references do
|
124
|
+
belongs_to :bar
|
125
|
+
end
|
126
|
+
create_model "Bar"
|
127
|
+
assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
|
128
|
+
end
|
129
|
+
|
130
|
+
test "foreign_key should return true if it is used in a remote association" do
|
131
|
+
create_model "Foo", :bar => :references
|
132
|
+
create_model "Bar" do
|
133
|
+
has_many :foos
|
134
|
+
end
|
135
|
+
assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
|
136
|
+
end
|
137
|
+
|
138
|
+
test "timestamp should return false by default" do
|
139
|
+
create_model "Foo", :created => :datetime
|
140
|
+
assert_equal false, create_attribute(Foo, "created").timestamp?
|
141
|
+
end
|
142
|
+
|
143
|
+
test "timestamp should return true if it is named created_at/on or updated_at/on" do
|
144
|
+
create_model "Foo", :created_at => :string, :updated_at => :string, :created_on => :string, :updated_on => :string
|
145
|
+
assert_equal [true] * 4, [create_attribute(Foo, "created_at"), create_attribute(Foo, "updated_at"),
|
146
|
+
create_attribute(Foo, "created_on"), create_attribute(Foo, "updated_on")].collect(&:timestamp?)
|
147
|
+
end
|
148
|
+
|
149
|
+
test "inheritance should return false by default" do
|
150
|
+
create_model "Foo", :type => :string, :alternative => :string do
|
151
|
+
self.inheritance_column = :alternative
|
152
|
+
end
|
153
|
+
assert_equal false, create_attribute(Foo, "type").inheritance?
|
154
|
+
end
|
155
|
+
|
156
|
+
test "inheritance should return if this column is used for single table inheritance" do
|
157
|
+
create_model "Foo", :type => :string, :alternative => :string do
|
158
|
+
self.inheritance_column = :alternative
|
159
|
+
end
|
160
|
+
assert_equal true, create_attribute(Foo, "alternative").inheritance?
|
161
|
+
end
|
162
|
+
|
163
|
+
test "content should return true by default" do
|
164
|
+
create_model "Foo", :my_first_column => :string
|
165
|
+
assert_equal true, create_attribute(Foo, "my_first_column").content?
|
166
|
+
end
|
167
|
+
|
168
|
+
test "content should return false for primary keys, foreign keys, timestamps and inheritance columns" do
|
169
|
+
create_model "Book", :type => :string, :created_at => :datetime, :case => :references do
|
170
|
+
belongs_to :case
|
171
|
+
end
|
172
|
+
create_model "Case"
|
173
|
+
assert_equal [false] * 4, %w{id type created_at case_id}.map { |a| create_attribute(Book, a).content? }
|
174
|
+
end
|
175
|
+
|
176
|
+
# Type descriptions ========================================================
|
177
|
+
test "type_description should return short type description" do
|
178
|
+
create_model "Foo", :a => :binary
|
179
|
+
assert_equal "binary", create_attribute(Foo, "a").type_description
|
180
|
+
end
|
181
|
+
|
182
|
+
test "type_description should return short type description if unsupported by rails" do
|
183
|
+
create_model "Foo"
|
184
|
+
ActiveRecord::Schema.define do
|
185
|
+
suppress_messages do
|
186
|
+
add_column "foos", "a", "REAL"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
assert_equal "real", create_attribute(Foo, "a").type_description
|
190
|
+
end
|
191
|
+
|
192
|
+
test "type_description should return short type description without limit if standard" do
|
193
|
+
with_native_limit :string, 456 do
|
194
|
+
create_model "Foo"
|
195
|
+
add_column :foos, :my_str, :string, :limit => 255
|
196
|
+
ActiveRecord::Base.connection.native_database_types[:string]
|
197
|
+
assert_equal "string (255)", create_attribute(Foo, "my_str").type_description
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
test "type_description should return short type description with limit if nonstandard" do
|
202
|
+
with_native_limit :string, 456 do
|
203
|
+
create_model "Foo"
|
204
|
+
add_column :foos, :my_str, :string, :limit => 456
|
205
|
+
assert_equal "string", create_attribute(Foo, "my_str").type_description
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
test "type_description should append hair space and low asterisk if field is mandatory" do
|
210
|
+
create_model "Foo", :a => :integer do
|
211
|
+
validates_presence_of :a
|
212
|
+
end
|
213
|
+
assert_equal "integer ∗", create_attribute(Foo, "a").type_description
|
214
|
+
end
|
215
|
+
|
216
|
+
test "type_description should return short type description with scale and precision for decimal types if nonstandard" do
|
217
|
+
create_model "Foo"
|
218
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
219
|
+
assert_equal "decimal (5,2)", create_attribute(Foo, "num").type_description
|
220
|
+
end
|
221
|
+
|
222
|
+
test "limit should return nil if there is no limit" do
|
223
|
+
create_model "Foo"
|
224
|
+
add_column :foos, :my_txt, :text
|
225
|
+
assert_equal nil, create_attribute(Foo, "my_txt").limit
|
226
|
+
end
|
227
|
+
|
228
|
+
test "limit should return nil if equal to standard database limit" do
|
229
|
+
with_native_limit :string, 456 do
|
230
|
+
create_model "Foo"
|
231
|
+
add_column :foos, :my_str, :string, :limit => 456
|
232
|
+
assert_equal nil, create_attribute(Foo, "my_str").limit
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
test "limit should return limit if nonstandard" do
|
237
|
+
with_native_limit :string, 456 do
|
238
|
+
create_model "Foo"
|
239
|
+
add_column :foos, :my_str, :string, :limit => 255
|
240
|
+
assert_equal 255, create_attribute(Foo, "my_str").limit
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
test "limit should return precision for decimal columns if nonstandard" do
|
245
|
+
create_model "Foo"
|
246
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
247
|
+
assert_equal 5, create_attribute(Foo, "num").limit
|
248
|
+
end
|
249
|
+
|
250
|
+
test "limit should return nil for decimal columns if equal to standard database limit" do
|
251
|
+
create_model "Foo"
|
252
|
+
add_column :foos, :num, :decimal
|
253
|
+
assert_equal nil, create_attribute(Foo, "num").limit
|
254
|
+
end
|
255
|
+
|
256
|
+
test "limit should return nil if type is unsupported by rails" do
|
257
|
+
create_model "Foo"
|
258
|
+
ActiveRecord::Schema.define do
|
259
|
+
suppress_messages do
|
260
|
+
add_column "foos", "a", "REAL"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
assert_equal nil, create_attribute(Foo, "a").limit
|
264
|
+
end
|
265
|
+
|
266
|
+
test "limit should return nil for oddball column types that misuse the limit attribute" do
|
267
|
+
create_model "Business", :location => :integer
|
268
|
+
attribute = create_attribute(Business, "location")
|
269
|
+
attribute.column.class_eval do
|
270
|
+
define_method :limit do
|
271
|
+
# https://github.com/voormedia/rails-erd/issues/21
|
272
|
+
{ :srid => 4326, :type => "point", :geographic => true }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
assert_equal nil, attribute.limit
|
276
|
+
end
|
277
|
+
|
278
|
+
test "scale should return scale for decimal columns if nonstandard" do
|
279
|
+
create_model "Foo"
|
280
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
281
|
+
assert_equal 2, create_attribute(Foo, "num").scale
|
282
|
+
end
|
283
|
+
|
284
|
+
test "scale should return nil for decimal columns if equal to standard database limit" do
|
285
|
+
create_model "Foo"
|
286
|
+
add_column :foos, :num, :decimal
|
287
|
+
assert_equal nil, create_attribute(Foo, "num").scale
|
288
|
+
end
|
289
|
+
|
290
|
+
test "scale should return zero for decimal columns if left to default setting when specifying precision" do
|
291
|
+
create_model "Foo"
|
292
|
+
add_column :foos, :num, :decimal, :precision => 5
|
293
|
+
assert_equal 0, create_attribute(Foo, "num").scale
|
294
|
+
end
|
295
|
+
|
296
|
+
test "scale should return nil if type is unsupported by rails" do
|
297
|
+
create_model "Foo"
|
298
|
+
ActiveRecord::Schema.define do
|
299
|
+
suppress_messages do
|
300
|
+
add_column "foos", "a", "REAL"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
assert_equal nil, create_attribute(Foo, "a").scale
|
304
|
+
end
|
305
|
+
|
306
|
+
test "scale should return nil for oddball column types that misuse the scale attribute" do
|
307
|
+
create_model "Kobold", :size => :integer
|
308
|
+
attribute = create_attribute(Kobold, "size")
|
309
|
+
attribute.column.class_eval do
|
310
|
+
define_method :scale do
|
311
|
+
1..5
|
312
|
+
end
|
313
|
+
end
|
314
|
+
assert_equal nil, attribute.scale
|
315
|
+
end
|
316
|
+
end
|